npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lyzr-architect

v0.1.2

Published

Per-app MongoDB database layer with RLS, auth scaffolding, and React components for Architect apps

Readme

lyzr-architect

Per-app MongoDB database layer with row-level security, authentication, and React components for Architect apps.

Features

  • MongoDB connection with DocumentDB compatibility
  • Row-level security (RLS) — Mongoose plugin auto-scopes all queries by owner_user_id
  • Auth scaffolding — email/password registration, login, JWT sessions
  • React components — AuthProvider, LoginForm, RegisterForm, ProtectedRoute, UserMenu
  • Pre-built API routes — mount /api/auth/* with one line each

Install

npm install lyzr-architect

Environment Variables

These are automatically injected into the sandbox by the backend:

DATABASE_URL=mongodb://user:pass@host:port/db
APP_JWT_SECRET=<random-secret>
DATABASE_NAME=app_myapp
DATABASE_PROVIDER=mongodb

Quick Start

1. Initialize the database

// lib/db.ts
import { initDB } from 'lyzr-architect';

// Connects to MongoDB using DATABASE_URL, registers RLS plugin globally.
// Idempotent — safe to call multiple times.
await initDB();

2. Define models

// models/task.ts
import { createModel } from 'lyzr-architect';

// createModel auto-adds: owner_user_id (for RLS), created_at, updated_at
// Do NOT add these fields manually.
const Task = createModel('Task', {
  title: { type: String, required: true },
  description: { type: String, default: '' },
  status: { type: String, enum: ['todo', 'in_progress', 'done'], default: 'todo' },
  due_date: { type: Date },
});

export default Task;

3. Mount auth routes

// app/api/auth/register/route.ts
import { handleRegister } from 'lyzr-architect';
export const POST = handleRegister;

// app/api/auth/login/route.ts
import { handleLogin } from 'lyzr-architect';
export const POST = handleLogin;

// app/api/auth/logout/route.ts
import { handleLogout } from 'lyzr-architect';
export const POST = handleLogout;

// app/api/auth/me/route.ts
import { handleMe } from 'lyzr-architect';
export const GET = handleMe;

4. Protect API routes

// app/api/tasks/route.ts
import { authMiddleware, initDB } from 'lyzr-architect';
import Task from '@/models/task';

// authMiddleware extracts JWT from cookie/header, sets RLS context.
// All queries are automatically scoped to the current user.
export const GET = authMiddleware(async (req) => {
  await initDB();
  const tasks = await Task.find(); // Auto-filtered by owner_user_id
  return Response.json({ tasks });
});

export const POST = authMiddleware(async (req) => {
  await initDB();
  const body = await req.json();
  const task = await Task.create({ title: body.title, status: body.status });
  // owner_user_id is auto-set to the current user
  return Response.json({ task });
});

For public routes that optionally show user data, use optionalAuth:

import { optionalAuth, initDB } from 'lyzr-architect';

export const GET = optionalAuth(async (req) => {
  await initDB();
  if (req.userId) {
    // Logged in — return user-specific data
  } else {
    // Not logged in — return public data
  }
});

5. Add React components

// app/layout.tsx
import { AuthProvider } from 'lyzr-architect/client';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AuthProvider>{children}</AuthProvider>
      </body>
    </html>
  );
}
// app/login/page.tsx
'use client';
import { LoginForm, RegisterForm } from 'lyzr-architect/client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';

export default function LoginPage() {
  const [isRegister, setIsRegister] = useState(false);
  const router = useRouter();

  if (isRegister) {
    return (
      <RegisterForm
        onSuccess={() => router.push('/dashboard')}
        onSwitchToLogin={() => setIsRegister(false)}
      />
    );
  }

  return (
    <LoginForm
      onSuccess={() => router.push('/dashboard')}
      onSwitchToRegister={() => setIsRegister(true)}
    />
  );
}
// app/dashboard/page.tsx
'use client';
import { ProtectedRoute, UserMenu, useAuth } from 'lyzr-architect/client';

export default function Dashboard() {
  const { user } = useAuth();

  return (
    <ProtectedRoute>
      <header>
        <h1>Dashboard</h1>
        <UserMenu />
      </header>
      <p>Welcome, {user?.name || user?.email}</p>
    </ProtectedRoute>
  );
}

API Reference

Server-side (lyzr-architect)

| Export | Description | |--------|-------------| | initDB() | Connect to MongoDB and register RLS plugin. Call before using models. | | createModel(name, schema) | Create a Mongoose model with auto owner_user_id, created_at, updated_at. | | authMiddleware(handler) | Wrap API route — requires auth, sets RLS context. Returns 401 if no token. | | optionalAuth(handler) | Wrap API route — sets RLS context if token present, continues without if not. | | handleRegister | POST /api/auth/register{ email, password, name? } | | handleLogin | POST /api/auth/login{ email, password } | | handleLogout | POST /api/auth/logout | | handleMe | GET /api/auth/me — returns current user or { user: null } | | signToken(payload) | Sign a JWT with APP_JWT_SECRET | | verifyToken(token) | Verify and decode a JWT | | hashPassword(password) | bcrypt hash | | verifyPassword(password, hash) | bcrypt compare | | UserModel | Mongoose model for _users collection (system collection, RLS-exempt) | | rlsPlugin | The Mongoose global plugin (registered automatically by initDB()) | | runWithContext(ctx, fn) | Run a function with a specific RLS context | | getCurrentUserId() | Get the current user ID from RLS context |

Client-side (lyzr-architect/client)

| Export | Description | |--------|-------------| | <AuthProvider> | React context provider. Wrap your app with this. Props: basePath? (default: /api/auth) | | <LoginForm> | Login form. Props: onSuccess?, onSwitchToRegister?, className? | | <RegisterForm> | Registration form. Props: onSuccess?, onSwitchToLogin?, className? | | <ProtectedRoute> | Auth guard. Props: loadingFallback?, unauthenticatedFallback?, loginPath? | | <UserMenu> | User avatar dropdown with logout. Props: className? | | useAuth() | Hook returning { user, isLoading, login, register, logout, refreshUser } |

How RLS Works

The RLS plugin is a Mongoose global plugin that:

  1. Adds owner_user_id field to every model (except system collections)
  2. Auto-filters all queries (find, findOne, update, delete, etc.) by owner_user_id
  3. Auto-sets owner_user_id on save and insertMany
  4. Blocks direct access to system collections (_users, _sessions)

This means User A can never see User B's data, even if the app code doesn't filter by user.

DocumentDB Compatibility

The package is compatible with both MongoDB and AWS DocumentDB:

  • Uses retryWrites: false
  • Standard mongodb:// connection strings only (no mongodb+srv://)
  • Standard query operators only (no $expr, no Map-Reduce)
  • RLS plugin uses where() conditions (maps to $and)

License

MIT