Litestore · Developer guide

Dependencies

Learn what the 81 runtime dependencies and 26 dev dependencies do, why zsa is patched, and how knip.json and check-unused-deps.ts keep the list from growing dead entries.

package.json declares 81 runtime dependencies and 26 dev dependencies, installed with Bun 1.2.2 (packageManager).

This page groups them by the job they do and names the real versions.

Two guards stop the list rotting. scripts/check-unused-deps.ts fails on a new runtime dependency nothing imports, and knip.json configures a broader unused export and file scan.

Framework and runtime

PackageDeclared versionWhat it does
next^16.1.1App Router, route handlers, next build
react / react-dom^19.2.3React 19
typescript^5.9.3dev only; tsc --noEmit is the typecheck
@t3-oss/env-nextjs^0.13.10typed env parsing in env.ts
server-only^0.0.1the marker check-client-bundle-server-only.ts traverses to
@sentry/nextjs^10.40.0error reporting

Database

Prisma is pinned to an exact version across three packages:

@prisma/client       7.4.2
@prisma/adapter-pg   7.4.2
prisma               7.4.2

There is no caret on any of them, so a minor release cannot drift the client away from the engine.

Between them they cover the schema, the migrations and the driver adapter over pg.

decimal.js-light (^2.5.1) is the decimal arithmetic behind ~/utils/money.

@types/pg (^8.16.0) supplies types for the adapter's driver.

One inconsistency is worth knowing about. The db:seed script is:

tsx prisma/seed.ts

tsx is not declared in package.json — it resolves from the environment. The prisma.seed entry in the same file uses:

bun prisma/seed.ts

The two paths to the seed disagree on the runner.

Commerce and payments

stripe (^20.3.1) covers checkout sessions, payment intents and webhook signature verification.

svix (^1.96.1) signs outbound webhooks, and jose (^6.1.3) signs and verifies JWTs.

better-auth (^1.4.19) owns sessions, sign-in and account records.

@upstash/redis (^1.36.0) and @upstash/ratelimit (^2.0.7) are the cache and the rate limiter. checkRateLimit fails open when Redis is unreachable, so an outage does not block sign-in.

AI

The AI layer is on the AI SDK 4 line, with three providers wired and selectable:

ai                    ^4.3.19
@ai-sdk/react         ^1.2.12
@ai-sdk/openai        ^1.3.24
@ai-sdk/anthropic     ^1.2.12
@ai-sdk/google        ^1.2.22
streamdown            ^2.3.0
use-stick-to-bottom   ^1.1.3

streamdown renders streamed markdown; use-stick-to-bottom handles chat scroll anchoring.

UI

Primitives come from radix-ui (^1.4.3), plus two separately versioned packages: @radix-ui/react-collapsible (^1.1.12) and @radix-ui/react-tabs (^1.1.13).

Styling is tailwindcss (^4.1.18, dev) with @tailwindcss/postcss, @tailwindcss/typography and tailwindcss-animate. cva and tailwind-merge (^3.4.0) back cx in ~/utils/cva.

Icons are lucide-react (^0.575.0), compiled into a sprite by scripts/build-icons.ts. Application code imports <Icon />, never lucide-react directly, and the icon-imports discipline rule enforces that.

Tables and forms:

  • @tanstack/react-table (^8.21.3)
  • react-hook-form (^7.70.0)
  • @hookform/resolvers (^3.10.0)
  • zod (^4.3.5)

The rich-text editor is TipTap 3, which arrives as six packages:

@tiptap/react
@tiptap/starter-kit
@tiptap/pm
@tiptap/extension-image
@tiptap/extension-link
@tiptap/markdown

The other inputs are react-day-picker (^9.13.0), react-colorful, react-phone-number-input, react-dropzone and cmdk.

Motion and charts:

  • motion (^12.38.0)
  • recharts (^3.6.0)
  • @number-flow/react
  • canvas-confetti
  • embla-carousel-react

Drag and drop is @atlaskit/pragmatic-drag-and-drop (^1.7.7) and its hitbox package.

State and URL handling:

  • nuqs (^2.8.6) for search-param state
  • swr (^2.3.8) for client fetching
  • zsa (^0.6.0) and zsa-react for server actions
  • sonner (^2.0.7) for toasts
  • next-themes
  • @mantine/hooks

One entry is not a version range at all: cva is declared as "beta", a dist-tag, so it resolves to whatever the current beta is at install time.

Content, email and media

@content-collections/core, /mdx and /next compile MDX content at build time, with rehype-slug and rehype-autolink-headings in the pipeline.

@react-email/components (^1.0.3) and resend (^6.9.2) are the email templates in emails/ and their delivery. react-email (dev) runs the preview server behind bun run email.

@aws-sdk/client-s3 and @aws-sdk/lib-storage (^3.962.0) provide S3-compatible object storage.

satori (^0.13.2) renders OG images, paired with loadGoogleFont in config/fonts.ts.

sanitize-html (^2.17.5) sanitises HTML and rss (^1.2.2) generates the feeds.

Background work and analytics

  • inngest (^3.54.0) — crons and domain-event handlers in functions/
  • @orpc/server / @orpc/shared (^1.13.9) — the narrow /api/rpc surface
  • posthog-js (^1.314.0) — client analytics
  • @atproto/api (^0.15.27) — Bluesky posting for the social module
  • wretch (^3.0.6) — the HTTP client for outbound integration calls

Utilities

The general-purpose helpers are:

  • date-fns (^4.1.0)
  • change-case
  • nanoid (^3.3.11)
  • plur
  • @primoui/utils

The no-primoui-formatters discipline rule keeps @primoui/utils out of formatting work that belongs to lib/formatters.ts.

Tooling

@biomejs/biome (^1.9.4) is the formatter and linter.

vitest (^4.0.18) runs the tests, with jsdom (^29.1.1) and vite (^7.3.1).

lefthook (^1.7.0) installs the git hooks, and knip (^5.64.4) is the unused-code scanner.

The remaining dev dependencies support the scripts and the build:

  • glob
  • fs-extra
  • node-html-parser
  • dotenv
  • schema-dts
  • postcss

The zsa patch

One dependency is patched:

package.json
"patchedDependencies": {
  "zsa@0.6.0": "patches/zsa@0.6.0.patch"
}

patches/ contains that single file.

The reason is a version mismatch in the type definitions: zsa 0.6.0 ships types written against zod 3, and the repository runs zod 4.

The patch rewrites dist/index.d.ts to declare local AnyZodObject and objectUtil.extendShape shims, and to drop the zod-3-only generic parameters from TZodMerge and the instanceofZodType* helpers.

It is a types-only change — no runtime behaviour is altered. Bun applies it on install.

Guarding against unused dependencies

scripts/check-unused-deps.ts runs as bun run lint:deps inside the lint:cleanliness aggregate.

It greps every .ts, .tsx, .mjs and .js file for import specifiers, reduces each to its top-level package name, and compares that set against package.json dependencies. Dev dependencies are out of scope.

Packages consumed by configuration rather than by an import are allowlisted in the script itself:

scripts/check-unused-deps.ts
const ALLOWLIST = [
  /^@types\//,
  /^tailwindcss$/,
  /^postcss/,
  /^autoprefixer$/,
  /^sharp$/, // next/image runtime
  /^@tiptap\/pm$/, // ProseMirror core — required peer of @tiptap/react, imported transitively
]

scripts/unused-deps-baseline.txt does not exist in the repository, and the script treats a missing baseline as an empty one.

The check therefore runs at zero tolerance today: every runtime dependency is imported somewhere, and adding one that is not fails the build immediately.

The wider knip scan

knip.json configures bun run lint:knip. Its entry points are:

  • the Next.js route conventions
  • functions/
  • scripts/
  • prisma/
  • instrumentation.ts
  • middleware.ts
  • the config files

The project set it scans covers:

app
components
server
services
lib
hooks
utils
events
types

Tests, stories and .d.ts files are ignored, and ignoreDependencies is empty.

Knip is not part of bun run verify or bun run lint — it is run on demand.

Inside the gate, the harness's own check-dead-components.ts, check-orphan-exports.ts and check-dead-server-actions.ts cover dead code.

Before adding a dependency

A runtime dependency has to be imported by real source code, or lint:deps fails on the next run. If it is consumed by configuration instead, it needs an entry in that script's ALLOWLIST, and that entry is the place to record why.

A patched dependency, like zsa, carries a file in patches/ that has to be revisited whenever that package is upgraded.

The question to ask is not whether the package works:

Which file will import it, and what does this repository do on the day it stops being maintained?

On this page