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

@scryan7371/sdr-security

v0.1.7

Published

Reusable auth/security capability for API and app clients.

Readme

sdr-security

Reusable auth/security capability for API and app clients.

Surfaces

  • api: shared auth types and input validation helpers.
  • app: typed client for auth endpoints.

API Integration

Use shared helpers/types in your API controllers/services where useful:

  • sanitizeEmail
  • isValidEmail
  • isStrongPassword
  • AuthResponse, RegisterResponse, SafeUser
  • notifyAdminsOnEmailVerified
  • notifyUserOnAdminApproval

Nest Integration

Import the Nest surface from @scryan7371/sdr-security/nest.

import { Module } from "@nestjs/common";
import {
  SecurityWorkflowsModule,
  SECURITY_WORKFLOW_NOTIFIER,
} from "@scryan7371/sdr-security/nest";
import { EmailService } from "./notifications/email.service";

@Module({
  imports: [
    SecurityWorkflowsModule.forRoot({
      notifierProvider: {
        provide: SECURITY_WORKFLOW_NOTIFIER,
        useFactory: (emailService: EmailService) => ({
          sendAdminsUserEmailVerified: ({ adminEmails, user }) =>
            emailService.sendEmailVerifiedNotificationToAdmins(
              adminEmails,
              user,
            ),
          sendUserAccountApproved: ({ email }) =>
            emailService.sendAccountApproved(email),
        }),
        inject: [EmailService],
      },
    }),
  ],
})
export class AppModule {}

User Table Ownership Model

Consuming apps keep ownership of their own app_user table. sdr-security stores security/auth state in its own tables and links them by user id.

  • App-owned table:
    • app_user (at minimum: id, email, plus any app-specific columns)
  • sdr-security tables:
    • security_user (password hash, verified/approved/active flags)
    • security_identity (provider links such as Google subject)
    • security_role, security_user_role
    • refresh_token
    • security_password_reset_token

Link key:

  • security_* .user_id -> app_user.id

This lets each app evolve its user schema independently while reusing the same security workflows, guards, controllers, and migrations.

Typical app query pattern is a join when you need security state:

SELECT u.id, u.email, su.is_active, su.admin_approved_at, su.email_verified_at
FROM app_user u
LEFT JOIN security_user su ON su.user_id = u.id
WHERE u.id = $1;

Nest/TypeORM equivalent:

const row = await usersRepo
  .createQueryBuilder("user")
  .leftJoin("security_user", "securityUser", "securityUser.user_id = user.id")
  .select("user.id", "id")
  .addSelect("user.email", "email")
  .addSelect("securityUser.is_active", "isActive")
  .addSelect("securityUser.admin_approved_at", "adminApprovedAt")
  .addSelect("securityUser.email_verified_at", "emailVerifiedAt")
  .where("user.id = :id", { id: userId })
  .getRawOne();

Optional Swagger setup in consuming app:

import { setupSecuritySwagger } from "@scryan7371/sdr-security/nest";

setupSecuritySwagger(app); // default path: /docs/security

Routes exposed by the shared controller:

  • POST /security/auth/register
  • POST /security/auth/login
  • POST /security/auth/forgot-password
  • POST /security/auth/reset-password
  • GET /security/auth/verify-email?token=...
  • POST /security/auth/change-password (JWT required)
  • POST /security/auth/logout (JWT required)
  • POST /security/auth/refresh
  • GET /security/auth/me/roles (JWT required)
  • POST /security/workflows/users/:id/email-verified
    • marks email_verified_at and notifies admins.
  • PATCH /security/workflows/users/:id/admin-approval with { approved: boolean }
    • updates admin_approved_at and notifies user when approved (admin JWT required).
  • PATCH /security/workflows/users/:id/active with { active: boolean } (admin JWT required)
  • GET /security/workflows/roles (admin JWT required)
  • POST /security/workflows/roles (admin JWT required)
  • DELETE /security/workflows/roles/:role (admin JWT required)
  • GET /security/workflows/users/:id/roles (admin JWT required)
  • PUT /security/workflows/users/:id/roles (admin JWT required)
  • POST /security/workflows/users/:id/roles with { role: string } (admin JWT required)
  • DELETE /security/workflows/users/:id/roles/:role (admin JWT required)

Shared notification workflows

Use these helpers to standardize notification behavior across apps while still keeping app-specific email sending in your own services.

import { api as sdrSecurity } from "@scryan7371/sdr-security";

await sdrSecurity.notifyAdminsOnEmailVerified({
  user: {
    id: user.id,
    email: user.email,
  },
  listAdminEmails: () => usersService.listAdminEmails(),
  notifyAdmins: ({ adminEmails, user }) =>
    emailService.sendEmailVerifiedNotificationToAdmins(adminEmails, user),
});

await sdrSecurity.notifyUserOnAdminApproval({
  approved: body.approved,
  user: {
    email: user.email,
  },
  notifyUser: ({ email }) => emailService.sendAccountApproved(email),
});

App Integration

Create one client per app session and reuse it across screens:

import { app as sdrSecurity } from "@scryan7371/sdr-security";

const securityClient = sdrSecurity.createSecurityClient({
  baseUrl,
  getAccessToken: () => accessToken,
});

Methods:

  • register
  • login
  • loginWithGoogle
  • refresh
  • revoke
  • logout
  • requestEmailVerification
  • verifyEmail
  • requestPhoneVerification
  • verifyPhone

Publish (npmjs)

  1. Configure project-local npm auth (.npmrc):
registry=https://registry.npmjs.org/
@scryan7371:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
  1. Set token, bump version, and publish:
export NPM_TOKEN=xxxx
npm version patch
npm publish --access public --registry=https://registry.npmjs.org --userconfig .npmrc
  1. Push commit and tags:
git push
git push --tags

CI Publish (GitHub Actions)

Tag pushes like sdr-security-v* trigger .github/workflows/publish.yml.

Required repo secret:

  • NPM_TOKEN (npm granular token with read/write + bypass 2FA for automation).

Install

Install a pinned version:

npm install @scryan7371/[email protected]

Database Integration Test

A sample Postgres integration test is included at:

  • src/integration/database.integration.test.ts

Run it with:

npm run test:db

Configuration resolution order:

  1. .env.test (if present)
  2. .env.dev (if present)
  3. existing process env

Supported env vars:

  • SECURITY_TEST_DATABASE_URL (preferred)
  • or DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME
  • optional fallback: DATABASE_URL
  • optional debug:
    • SECURITY_TEST_KEEP_SCHEMA=true (do not drop schema after test run)
    • SECURITY_TEST_SCHEMA=your_schema_name (use fixed schema name)

See .env.test.example for a template.

Release Script

You can automate version bump + tag + push with:

npm run release:patch
npm run release:minor
npm run release:major

What it does:

  1. Verifies clean git working tree
  2. Runs npm test
  3. Runs npm run build
  4. Bumps package.json + package-lock.json
  5. Commits as chore(release): vX.Y.Z
  6. Tags as sdr-security-vX.Y.Z
  7. Pushes commit and tag

This tag format triggers .github/workflows/publish.yml.