Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@justwant

A backend. A database. A storage bucket.
That's a complete platform.

@justwant/* is a TypeScript-first library ecosystem that covers authentication, observability, billing, notifications, file storage, and much more — using infrastructure you already own.

import { createAudit }     from '@justwant/audit'
import { integrityPlugin } from '@justwant/audit/plugin-integrity'
import { pgAdapter }       from '@justwant/audit/adapter-pg'

const audit = createAudit({
  adapter: pgAdapter(pool),
  plugins: [integrityPlugin()],
})

What's included

With a backend, a database, and a storage bucket, you now have:

Authentication · Permissions · Consent · Audit trail · Observability · Analytics · File storage · Notifications · Webhooks · Rate limiting · Feature flags · API key management · Scheduled jobs · Task queues · Billing · CMS · Session replay · Onboarding · Real-time · Data pipeline · Waitlist

No vendor lock-in. No data leaving your infrastructure. No third-party terms applied to your users.


Packages

Foundation

Small, focused packages with no inter-package dependencies. Everything else is built on top of these.

Package Role
@justwant/meta Type primitives. Inspectable<N> (named config objects), Definable<N> (callable factories), RefLike<T> (entity references)
@justwant/db Data Access Layer. Contracts, Drizzle, Prisma, Waddler. defineContract(), AdapterError, createDrizzleAdapter
@justwant/plugin Plugin system. createPlugin(), dependency graph, declaration merging
@justwant/id ID generation. ulid(), uuid(), prefixed('key')key_01J8X
@justwant/crypto HMAC, hash, sign, verify, encrypt, decrypt
@justwant/env Typed environment variables. Zod schema, coercion, expansion, redaction
@justwant/lock Distributed locks. acquire(key, fn, { ttl })
@justwant/retry Retry with backoff. Exponential, linear, and fixed strategies
@justwant/event Internal event bus. Decouples packages from each other
@justwant/context Request context propagation via AsyncLocalStorage
@justwant/cookie Cookie read/write. Signed, httpOnly, sameSite, __Host- prefix
@justwant/config Multi-source config with waterfall resolution. get(), watch, cache

Building blocks

Packages that combine foundation primitives into reusable cross-cutting concerns.

Package Role
@justwant/job Scheduled jobs. Pluggable runners (Node, Cloudflare, Vercel, QStash)
@justwant/queue Event-triggered jobs. Steps, durability, fan-out, sleep
@justwant/storage File upload/download. Multipart, lifecycle, signed URLs, scan, transform
@justwant/protect HTTP security. Rate limiting, IP intelligence, bot detection, WAF
@justwant/flag Feature flags. Typed evaluation, rollout, targeting, A/B
@justwant/preference User preferences. Namespaced, typed, global → plan → user inheritance
@justwant/consent GDPR consent. History, versioning, legal proof, expiry, right to erasure
@justwant/permission RBAC/ABAC. Roles, ownership, delegation, hierarchy, scope
@justwant/audit Immutable event log. HMAC chaining, redaction, retention, export
@justwant/webhook Outbound webhooks. Signing, retry, dead-letter, delivery tracking
@justwant/notify Multi-channel notifications. Templates, routing, digest, deduplication

Features

Higher-level packages that expose direct product value, built entirely on top of the two groups above.

Package Replaces What it does
@justwant/auth Auth0, Clerk Sessions, OAuth 40+, 2FA, passkeys, organizations, SCIM
@justwant/keys Unkey, Zuplo Hashed API keys, per-key rate limits, credits, rotation
@justwant/analytics Plausible, Mixpanel Events, sessions, funnels, retention, privacy-first
@justwant/monitor Sentry, Bugsnag Error tracking, performance, source maps, alerting
@justwant/billing Stripe Billing, Paddle Plans, credits, usage-based billing, trials, dunning
@justwant/cms Contentful, Sanity Typed schemas, CRUD, versioning, preview, i18n, media
@justwant/support Intercom, Crisp Conversations, tickets, agents, automatic user context
@justwant/onboarding Userflow, Appcues Steps, progress tracking, nudges, completion hooks
@justwant/waitlist Custom solutions Sign-up, referral, position, batch invitations
@justwant/pipeline Segment, RudderStack Sources → transforms → destinations, event fan-out
@justwant/feature PostHog, Hotjar Session replay, heatmaps, surveys, breadcrumbs

How it works

Adapter pattern

Every package that touches persistence accepts an adapter. You bring the database — the package brings the logic.

import { createAudit }    from '@justwant/audit'
import { prismaAdapter }  from '@justwant/audit/adapter-prisma'
import { drizzleAdapter } from '@justwant/audit/adapter-drizzle'
import { pgAdapter }      from '@justwant/audit/adapter-pg'

// Pick what matches your stack
const audit = createAudit({ adapter: prismaAdapter(prismaClient) })
const audit = createAudit({ adapter: drizzleAdapter(db, { schema }) })
const audit = createAudit({ adapter: pgAdapter(pool) })

// Or implement the contract directly for anything else
const audit = createAudit({
  adapter: {
    async insert(event) { /* your logic */ },
    async findMany(filters) { /* your logic */ },
  },
})

Plugin system

Each package has a minimal core. Features are opt-in plugins — imported explicitly, so bundlers only include what you actually use.

import { createAudit }     from '@justwant/audit'
import { integrityPlugin } from '@justwant/audit/plugin-integrity'
import { retentionPlugin } from '@justwant/audit/plugin-retention'
import { streamPlugin }    from '@justwant/audit/plugin-stream'
import { pgAdapter }       from '@justwant/audit/adapter-pg'

const audit = createAudit({
  adapter: pgAdapter(pool),
  plugins: [
    integrityPlugin(),
    retentionPlugin({ after: '90d', action: 'anonymize' }),
    streamPlugin({ destination: webhookAdapter() }),
  ],
})

Subpath exports

Adapters and plugins are isolated subpath exports. Your bundler only loads what you import — nothing else is included.

// Only these files end up in your bundle
import { createAudit }     from '@justwant/audit'
import { integrityPlugin } from '@justwant/audit/plugin-integrity'
import { pgAdapter }       from '@justwant/audit/adapter-pg'

// Other adapters are never loaded, never bundled
// @justwant/audit/adapter-prisma
// @justwant/audit/adapter-drizzle

Declaration merging

Plugins extend types without patching the core. The result is always fully typed, inferred directly from your config.

// With creditsPlugin and rateLimitPlugin active on @justwant/keys:
const result = await keys.verify('sk_live_abc123')

result.valid               // always present
result.credits.remaining   // typed — only when creditsPlugin is active
result.rateLimit.reset     // typed — only when rateLimitPlugin is active
result.permissions         // typed — only when permissionPlugin is active

Getting started

# Add the packages you need
pnpm add @justwant/auth @justwant/audit

# Peer dependencies — install only what your adapters require
pnpm add drizzle-orm  # Drizzle adapters

Schema generation

# Generate SQL migrations for all active packages
npx justwant migrate generate --dialect postgres

# For your ORM
npx justwant migrate generate --adapter prisma   # outputs Prisma model blocks
npx justwant migrate generate --adapter drizzle  # outputs table definitions

Repository structure

@justwant/
├── packages/
│   ├── meta/          # Foundation
│   ├── adapter/
│   ├── plugin/
│   ├── id/
│   ├── crypto/
│   ├── env/
│   ├── cache/
│   ├── lock/
│   ├── retry/
│   ├── event/
│   ├── context/
│   ├── cookie/
│   ├── config/
│   │
│   ├── job/           # Building blocks
│   ├── queue/
│   ├── storage/
│   ├── protect/
│   ├── flag/
│   ├── preference/
│   ├── consent/
│   ├── permission/
│   ├── audit/
│   ├── webhook/
│   ├── notify/
│   │
│   ├── auth/          # Features
│   ├── keys/
│   ├── analytics/
│   ├── monitor/
│   ├── billing/
│   ├── cms/
│   ├── support/
│   ├── onboarding/
│   ├── waitlist/
│   ├── pipeline/
│   └── feature/
│
├── docs/
└── examples/          # Next.js, Nuxt, Hono, Express

Dependency rule: Foundation packages import nothing from this repo. Building blocks import Foundation only. Features import both — but never each other. Cross-feature communication goes through @justwant/event.


Contributing

This is a pnpm workspace monorepo.

pnpm install                # install all dependencies
pnpm build                  # build all packages
pnpm test                   # run all tests
cd packages/db && pnpm dev  # work on a single package

Each package has its own CONTRIBUTING.md with adapter and plugin authoring guidelines.


License

MIT — see LICENSE

About

TypeScript-first library ecosystem that covers authentication, observability, billing, notifications, file storage, and much more

Resources

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages