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

@stnd/modules

v0.5.1

Published

--- title: "@stnd/modules" aliases: [] created: 2026-07-04 23:28 modified: 2026-07-05 19:23 last_audited: 2026-07-14 audit_interval_days: 90 next_audit: 2026-10-12 audit_priority: 3 maturity: tree mode: read publish: false status: active tags: - package

Readme


title: "@stnd/modules" aliases: [] created: 2026-07-04 23:28 modified: 2026-07-05 19:23 last_audited: 2026-07-14 audit_interval_days: 90 next_audit: 2026-10-12 audit_priority: 3 maturity: tree mode: read publish: false status: active tags:

  • package
  • stnd theme: kernel type: package visibility: private

@stnd/modules

The spine of the Standard application.

@stnd/modules is the discovery engine and runtime loader for the Standard vertical slice architecture. Each *.module.js manifest declares a self-contained section of your application — routes, styles, components, middleware, and actions in one folder.

The name reflects the modular, self-contained units of the application. Remove one, and that feature disappears cleanly.

ELI5

A “module” is one feature, in one folder: its routes, its styles, its components, all together. Want to add an RSS feed? moduleLoad: ["@stnd/modules/rss"] and it’s there — routes and all. Want to remove a feature entirely? Delete its folder. Nothing else in the app needs to know or change. This is the pattern behind everything: Standard itself ships as a pile of small modules (@stnd/modules/robots, /sitemap, /rss, /toast…) rather than one big framework blob.

Use a built-in module (in astro.config.mjs):

standard({ moduleLoad: ["@stnd/modules/rss", "@stnd/modules/humans"] });

Make your own: stnd module <name> (see packages/cli) scaffolds modules/<name>/index.module.js for you.

Manifest Schema

A module manifest must be named *.module.{js,ts} (convention: index.module.js) and export default { … } with this shape:

// REQUIRED
id: string                // unique module id (e.g., "my-feature")
name: string              // human-friendly label
description?: string      // human-friendly description

// Conditional Loading
status?: "disabled"       // skip this module entirely
environment?: string | string[]
  // Restrict to specific Astro commands: "dev", "build", "preview"
  // Accepts a single string or an array (e.g., ["dev", "preview"])
  // Omit to load in all environments (default)

// Unified Hooks (Logic & Interface)
// ---------------------------------------------------------------------------
// Standard automatically routes hooks based on their file extension:
// - .js, .ts             -> LOGIC  (Listeners / Handlers)
// - .astro, .svelte, .md -> UI     (Components / Plugs)
//
// These can be a single string or an array of entries.
hooks?: {
  [hookName: string]: string | Array<string | HookEntry>
}

// Routes (Astro)
routes?: Array<{
  path: string          // URL pattern (e.g., "/robots.txt")
  entrypoint: string    // relative to folio dir (e.g., "./route.js" or "./route.astro")
}>

// Styles
// - starts with "@" → imported as-is (package import)
// - else resolved relative to module dir and injected via injectScript("page-ssr")
styles?: string[]

// Scripts
// - starts with "@" → imported as-is
// - else resolved relative to module dir and injected on the client page
scripts?: string[]

// Head entries
// - string → imported like styles (SSR import)
// - { inline: string } → injected as inline head script
head?: Array<string | { inline: string }>

// Middleware
// - string → entrypoint, order defaults to 0
// - { entrypoint: string; order?: number }
middleware?: Array<string | { entrypoint: string; order?: number }>

// Astro integrations (passed through)
integrations?: Array<any>

// Actions (Astro Actions)
// - string → path to file exporting actions object(s)
actions?: string

// Content Collections
// - string → path to file exporting collections (e.g., "./content.ts")
content?: string

// Dependencies (other modules this one requires)
dependencies?: string[]

Unified Hooks Architecture

The hooks object is the brain of your module. It handles both system events and UI injection.

1. Integration Hooks (Logic)

If the hook name starts with astro: or the entry ends in .js/.ts, it’s treated as logic.

// index.module.js
export default {
  id: "my-feature",
  hooks: {
    "astro:config:setup": "./hooks/setup.js", // Astro native hook
    "app:init": "./hooks/init.ts", // Custom app hook
  },
};

2. Interface Hooks (UI Plugs)

If the entry ends in .astro, .svelte, .md, or any other format, it’s treated as a UI component.

// index.module.js
export default {
  id: "my-feature",
  hooks: {
    "header:top": ["./components/Banner.astro"],
    "footer:bottom": "./components/Copyright.astro",
  },
};

Consuming Hooks

UI Rendering (Zones):

In your Layout or components, use the <Hook /> component to render all registered components for a hook ID.

---
import Hook from "@stnd/core/Hook";
---

<header>
  <Hook id="header:top" props={{ theme: "dark" }} />
</header>

Logic Execution:

Trigger logic hooks via the virtual module.

import { runHook } from "virtual:stnd/hooks";

await runHook("app:init", { some: "data" });

Middleware

Module middlewares are native Astro Middlewares. They must follow the (context, next) signature and call next() to continue the chain.

// index.module.js
export default {
  id: "auth",
  middleware: [{ entrypoint: "./middleware.js", order: -100 }],
};
// middleware.js
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async (context, next) => {
  // Root initialization, auth checks, etc.
  return next();
});

Content Extensions

Modules can define Astro Content Collections.

// index.module.js
export default {
  id: "my-feature",
  content: "./content.ts",
};
// content.ts
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";

export const myCollection = defineCollection({
  loader: glob({ pattern: "*.md", base: "./content/my-collection" }),
  schema: z.object({
    /* ... */
  }),
});

The application’s src/content.config.ts imports and merges these collections:

import { collections as moduleCollections } from "virtual:stnd/content";

export const collections = {
  ...moduleCollections,
};

Authoring Guide

  1. Place modules under modules/<name>/index.module.js at the project root.
  2. Keep logic inside the module; .astro files should only consume model instances.
  3. Import from sibling modules via @modules/<name> — this alias is auto-registered by @stnd/core.
  4. Prefer OKLCH and Standard tokens for styles; avoid one-off CSS.
  5. No backward compatibility — ship only the current shape.

The @modules Import Alias

@stnd/core automatically registers @modules as a Vite alias pointing to the app’s modules/ directory. Every app gets this for free — no manual tsconfig or Vite config needed.

import { Note } from "@modules/spine/models/Note";
import Author from "@modules/spine/models/Author";
import Base from "@modules/base/layouts/Base.astro";

The corresponding tsconfig.json path (for editor intellisense):

{
  "compilerOptions": {
    "paths": {
      "@modules/*": ["modules/*"]
    }
  }
}

Boundary Rules

Modules follow strict vertical slice isolation enforced by dependency-cruiser:

  • Foundation modules (models, core) — importable by any module
  • Feature modules (everything else) — must NOT import from sibling feature modules
  • One-way dependencies — features → foundation → @stnd/* packages, never reversed
  • No circular deps — within or across modules

Run the boundary check:

pnpm boundaries:gd    # Check Standard Garden
pnpm boundaries:ade   # Check L'art d'enseigner

Loader Behavior

  • Discovers **/*.module.{js,ts} in the configured moduleFolder (default: modules).
  • moduleLoad in astro.config accepts:
    • Bare names (auto-prefixed): "launcher", "design", etc.
    • Explicit specifiers: "@stnd/modules/design" or "./local/feature".
  • Routes, styles, scripts, head, middleware are injected per manifest.
  • Integrations are forwarded to Astro via updateConfig.
  • UI/Component extensions are exposed via virtual:stnd/components.
  • Client payload strips infrastructure keys; keeps __importPath for server use.

Disabling a Module

Prefix the folder name with _ to temporarily disable without deleting:

mv modules/export/ modules/_export/    # Disabled
mv modules/_export/ modules/export/    # Re-enabled

The loader skips any folders starting with _.

Environment-Gated Modules

Restrict a module to specific Astro commands (dev, build, or preview) using the environment field. The module is skipped entirely when the current command doesn’t match.

// Only loaded during `astro dev`
export default {
  id: "dev-tools",
  name: "Dev Tools",
  environment: "dev",
};

// Loaded during `astro dev` and `astro preview`, but not `astro build`
export default {
  id: "staging-tools",
  name: "Staging Tools",
  environment: ["dev", "preview"],
};

Omit the field to load in all environments (the default). When a module is skipped, its routes, styles, scripts, middleware, and hooks are completely absent from the build — as if the module didn’t exist.

Shipped Modules

These built-in modules come with @stnd/modules and can be loaded via moduleLoad:

Gold Standard (loaded by default)

Every @stnd site ships with these. Opt out via moduleExclude.

| Module | ID | Route | What it does | | :----------------------- | :-------------- | :------------------ | :----------------------------------------------------------------- | | @stnd/modules/styles | stnd-styles | — | Injects the Standard design stylesheet | | @stnd/modules/robots | stnd-robots | /robots.txt | Generates robots.txt from site config | | @stnd/modules/headers | stnd-headers | /_headers | Emits security headers (HSTS, X-Frame-Options, Permissions-Policy) | | @stnd/modules/manifest | stnd-manifest | /site.webmanifest | Serves the web app manifest | | @stnd/modules/sitemap | stnd-sitemap | — | Sitemap generation via @astrojs/sitemap |

Opt-In Modules

Load these explicitly via moduleLoad when your site needs them.

| Module | ID | Route | What it does | | :--------------------------- | :------------------ | :-------------------------- | :----------------------------------------------------- | | @stnd/modules/rss | stnd-rss | /rss.xml | Generates an RSS 2.0 feed from site content and config | | @stnd/modules/security-txt | stnd-security-txt | /.well-known/security.txt | RFC 9116 security contact disclosure | | @stnd/modules/humans | stnd-humans | /humans.txt | The people and tools behind the site | | @stnd/modules/themes | stnd-themes | — | Theme/temperament stylesheet injection | | @stnd/modules/lab | stnd-lab | — | StandardLab CSS inspector (dev tool) | | @stnd/modules/content | stnd-content | /[…slug] | Content collection catch-all route | | @stnd/modules/maintenance | stnd-maintenance | /maintenance | Maintenance mode with redirect middleware |

Usage in an App

Gold standard modules load automatically — just add your fonts, themes, and features:

// astro.config.mjs
import standard from "@stnd/core";

export default defineConfig({
  integrations: [
    standard({
      // Gold standard modules load automatically:
      //   styles, robots, headers, manifest, sitemap, @stnd/fonts/inter

      // Add your own modules on top of the defaults
      moduleLoad: [
        "@stnd/modules/rss",
        "@stnd/modules/humans",
        "@stnd/modules/security-txt",
        "@stnd/fonts/kalice",
        "@stnd/themes/editorial",
      ],
    }),
  ],
});

To opt out of a specific default, use moduleExclude:

standard({
  // Everything except the sitemap
  moduleExclude: ["@stnd/modules/sitemap"],
  moduleLoad: ["@stnd/modules/rss"],
});

Philosophy

  • Vertical slice: each module is self-contained — a section of the application.
  • Strict boundaries: features don’t cross-import. Dependencies flow one way.
  • Zero shims: no legacy flags, no backward compatibility layers.
  • Performance and clarity: small, explicit manifests; no hidden magic.

Notes / Observations

(jot down anything noticed here — quirks, gotchas, ideas)

Todo

  • [ ] Nothing tracked yet. [priority:: 3] [token_scale:: 3] [created:: 2026-07-14] [area:: framework]

“A well-bound app holds together not because of glue, but because every module knows its place.”