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

lss-eslint-plugin

v0.1.0

Published

ESLint rules and folder structure preset for Layered Server Structure (LSS).

Readme

lss-eslint-plugin enforces the import boundaries in Layered Server Structure (LSS), keeps each backend feature independent of its siblings, and checks .route and .logic naming and per-verb limits. It ships an ESM bundle and TypeScript declarations built with tsdown, so consumers can use it directly without a build step.

Install it in your server project:

npm install --save-dev lss-eslint-plugin 'eslint@^10.12.0' typescript-eslint

Compose its flat configuration after your application's parser configuration:

import tseslint from 'typescript-eslint'
import lss from 'lss-eslint-plugin'

export default tseslint.config(
  ...tseslint.configs.recommended,
  ...lss.configs.recommended,
)

The consumer supplies its JavaScript/TypeScript parser configuration. Paths are relative to the consuming ESLint configuration, so a backend config in apps/backend applies the rules to that application's src directory. The plugin does not configure or replace no-restricted-imports; application-specific restrictions can run alongside these rules.

| Rule | Recommended files | Disallowed behavior | | -------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | lss/middleware-imports | src/**/middleware/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | routes path segments; .route and .logic modules | | lss/handler-imports | src/**/handlers/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | services, middleware, and routes path segments; .route and .logic modules | | lss/logic-imports | src/**/*.logic.{ts,js,mts,cts,mjs,cjs} | HTTP/WS router frameworks (hono, fastify, express, koa, h3, @nestjs/*), middleware, handlers, routes, and .route modules | | lss/service-imports | src/**/services/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | HTTP/WS router frameworks (hono, fastify, express, koa, h3, @nestjs/*), middleware, handlers, routes, .route, and .logic modules | | lss/pure-imports | src/**/{utils,schema,constants,types}/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | services, middleware, handlers, routes, .route, .logic, and runtime HTTP/WS router frameworks (import type of router packages is permitted in constants/types) | | lss/feature-imports | src/**/features/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | Imports that resolve into a different features/<feature> folder | | lss/encapsulate-features | src/**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | Shared layers importing features/, and callers outside features/<feature>/ bypassing <feature>.route to reach routes/ or feature internals | | lss/route-files | src/**/*.route.{ts,tsx,js,jsx,mjs,cjs,mts,cts} | index route names, verb-prefixed routes outside routes/<name>/, unprefixed routes inside routes/<name>/, and duplicate verbs in one folder | | lss/one-logic-per-folder | src/**/*.logic.{ts,js,mts,cts,mjs,cjs} | index logic names, misplaced verb modifiers, more than one unprefixed .logic at a feature root, or duplicate verb .logic files in one folder |

Middleware may import router helpers, services, handlers, schema/, utilities, constants, plain types, and other middleware, while staying free of .route and .logic modules so routes and middleware never form circular dependencies. Handlers may import router request/response helpers, plain types, utilities, constants, and other handlers. Services may import database drivers, ORMs, validation libraries, schema/, other services, utilities, constants, and plain types. utils/, schema/, constants/, and types/ stay free of services, middleware, handlers, routes, and .logic modules; constants/ and types/ may use import type for external framework option types without pulling runtime router code into pure layers. For application layers (services/, middleware/, handlers/, and sibling features/), type-only imports follow the same boundaries: move shared types into a types/ module instead of importing them through a forbidden layer.

The import rules inspect static imports, re-exports, import() expressions, unshadowed require() calls, TypeScript import types, and TypeScript import-equals declarations. String literals and template literals without expressions are checked. .route and .logic imports are recognized with or without source/output extensions. Directory imports such as ../services, Windows separators, and bundler query/fragment suffixes are also recognized.

Keep in mind that this is a static specifier check, not an import-graph resolver. Computed module names and indirect exports from otherwise permitted barrels aren't traced. Path aliases need to expose their layer segment (for example @/services/db); an opaque alias needs an application-specific restriction.

Keep features independent and encapsulated

lss/feature-imports applies to every source file inside a features/<feature> folder—including .route and .logic files, sub-routes under routes/<name>/, and feature-scoped middleware/, handlers/, services/, and utils/. It reports any import whose module path resolves into a sibling feature folder, such as ../messages/utils/schema from src/features/users/users.route.ts. Imports within the same feature (including from routes/by-id/ up to ../../utils/schema) and imports from shared src/ layers are allowed.

lss/encapsulate-features protects feature boundaries from the outside: shared layers (middleware/, handlers/, services/, schema/, utils/, constants/, and types/) may never import from features/, and server entry points such as src/app.ts must mount a feature through its root <feature>.route module (or index barrel) rather than reaching directly into features/<feature>/routes/<name>/ or internal helpers.

When two features—or a shared layer and a feature—need the same middleware, response handler, service, or schema, move it to the matching src/-level layer and make its interface generic enough for every consumer.

Route and logic file rules

lss/route-files enforces how endpoint files scale from single-route features to multi-route resources:

  • Feature root (features/<feature>/): Allows at most one unprefixed <feature>.route.ts file. A simple feature can define its route directly here; a multi-endpoint feature uses <feature>.route.ts to mount sub-routes from routes/<name>/. Verb-prefixed route files (such as users.get.route.ts) aren't allowed at the feature root.
  • Named sub-routes (features/<feature>/routes/<name>/): Use routes/index/ as the folder placeholder for / and descriptive kebab-case folders such as routes/by-id/ for sub-paths like /:id. Inside routes/<name>/, every .route file must carry a supported verb or transport modifier (get, post, put, patch, delete, options, head, ws, sse), and each folder may contain at most one .route file per verb (for example, users.get.route.ts and users.post.route.ts can live side by side in routes/index/, while a second .get.route.ts belongs in its own routes/<name>/ subfolder).
  • Descriptive filenames: Route files may never be named index.route.ts or index.<verb>.route.ts—even inside routes/index/. Name them after the resource (users.get.route.ts, user-by-id.get.route.ts) so open files stay readable in editor tabs.

lss/one-logic-per-folder applies the exact same rules to optional .logic.ts orchestration files (users.logic.ts at the feature root; users.get.logic.ts and users.post.logic.ts inside routes/index/). Colocated .spec.ts and .test.ts files don't count toward either limit. Run ESLint without --cache after adding, removing, or renaming sibling .route or .logic files.

Optional application structure

createLssConfig({ root }) combines lss.configs.recommended with a full TypeScript server folder and filename policy powered by eslint-plugin-project-structure:

import tseslint from 'typescript-eslint'
import { createLssConfig } from 'lss-eslint-plugin'

export default tseslint.config(
  ...tseslint.configs.recommended,
  ...createLssConfig({ root: import.meta.dirname }),
)

root must be the absolute application directory containing src; import.meta.dirname supplies it from the consuming eslint.config.js.

| Location | Accepted contents | | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | src | Shared layers, features, app.ts, index.ts, main.ts, server.ts, and their tests | | src/features/<feature> | At most one <feature>.route.ts and <feature>.logic.ts; tests, index.ts, routes/, and feature-scoped layers | | src/features/<feature>/routes/<route-name> | At most one <resource>.<verb>.route.ts and <resource>.<verb>.logic.ts per verb; tests, index.ts, and route-scoped layers | | middleware, handlers, schema | TypeScript modules, tests, and barrels | | services, constants, utils | TypeScript modules, tests, and barrels (services/schemas permits *.d.ts declarations; utils/testing-utils permits helpers) | | types | TypeScript modules and *.d.ts declarations | | assets | HTML, SQL, JSON, images, fonts, media, WebAssembly, and text assets |