npm package: @stnd/plugins
Description: Standard-Garden/apps/standard/plugins/README.md # Standard Plugins
Latest version: 0.2.0

Standard-Garden/apps/standard/plugins/README.md
# Standard Plugins

Standard is now a lean plugin loader. Each `*.plugin.js` exports a manifest the loader understands. This doc captures the schema and authoring guidance—no backward-compat shims.

## Manifest Schema

A plugin file must be named `index.plugin.js` and `export default { ... }` with this shape:

```/dev/null/plugin-schema.js#L1-120
// REQUIRED
id: string                // unique plugin id
name: string              // human-friendly label
description?: string      // human-friendly description
```

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

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

// Scripts
// - starts with "@" → imported as-is
// - else resolved relative to plugin 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

// Dependencies
// - List of plugin IDs that must be loaded before this plugin
dependencies?: string[]

// Hooks
// - Keys starting with "astro:" → Proxied to Astro integration hooks
// - Other keys → Treated as Custom Application Hooks available via virtual:standard/hooks
hooks?: {
  [hookName: string]: string
}

// Components (UI Zones)
// Map of zone → entries
// Supports both 'components' and 'extensions' keys.
// Entry can be:
// - string → component path (relative to plugin dir)
// - object → { component?: string; action?: string; meta?: object; trigger?: any }
components?: {
  [zone: string]: Array<
    | string
    | {
        component?: string
        action?: string
        meta?: Record<string, any>
        trigger?: any
      }
  >
}
// Alias for components
extensions?: Record<string, any[]>

// Notes:
// - Anything outside routes/styles/scripts/head/middleware/integrations/components is passed to the runtime (minus those fields) and tagged with __importPath for server-side use.
// - Bare names in pluginLoad are prefixed with "@stnd/astro/plugins/" automatically; package/external specifiers still resolve as given.
```

### Example: Custom Hooks & Components

Plugins can extend the application runtime or inject UI components into zones.

**Manifest (`my.plugin.js`):**

```javascript
export default {
  id: "my-plugin",
  name: "My Plugin",
  
  // Custom Hook: will be available via `virtual:standard/hooks`
  hooks: {
    "app:db:init": "./hooks/db-init.js"
  },

  // UI Component: inject into the 'backpack' zone
  // Can also use 'components' key
  extensions: {
    "backpack": [
      {
        component: "./components/MyWidget.svelte",
        meta: { "client:load": true }
      }
    ]
  }
}
```

**Hook Handler (`./hooks/db-init.js`):**

```javascript
export default async function(dbInstance) {
  console.log("Plugin initializing DB...", dbInstance);
  // Perform custom logic, migration, etc.
}
```

**Consuming Hooks (Application Code):**

```javascript
import { runHook } from "virtual:standard/hooks";

// Trigger all registered "app:db:init" hooks
await runHook("app:db:init", myDatabase);
```

### Middleware

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

**Manifest (`auth.plugin.js`):**
```javascript
export default {
  id: "auth-plugin",
  middleware: ["./middleware.js"]
}
```

**Middleware (`./middleware.js`):**
```javascript
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async (context, next) => {
  console.log("Plugin middleware running...");
  // You can wrap next(), modify the response, etc.
  return next();
});
```

## Authoring Guide

1) Place plugins under `plugins/<name>/index.plugin.js` at the project root.
2) Keep logic inside the plugin; `.astro` files should only consume model instances.
3) Prefer OKLCH and Standard tokens for styles; avoid one-off CSS unless you’re defining a temperament/theme.
4) No backward compatibility—ship only the current shape.

## Loader Behavior (Quick)

- Discovers `**/*.plugin.{js,ts}` in `pluginFolder` (default `src/plugins`; apps can override).
- `pluginLoad` accepts:
  - Bare names (auto-prefixed): `"design"`, `"themes"`, `"lab"`, etc.
  - Explicit specifiers: `"@vendor/some-plugin"` or `"./local/plugin.js"`.
- Routes, styles, scripts, head, middleware are injected per manifest.
- Integrations are forwarded to Astro via `updateConfig`.
- UI extensions are exposed via `virtual:standard/ui`.
- Client payload strips routes/styles/scripts/head/middleware/integrations/extensions; keeps `__importPath` for server use.

## Core Plugins (shipped)

- `design` — base stylesheet
- `themes` — temperament/theme stylesheet
- `lab` — StandardLab inspector bundle
- `content` — content route
- `robots` — robots.txt route
- `headers` — headers route
- `manifest` — web manifest route
- `sitemap` — sitemap generation

## Usage in an App

```/dev/null/astro.config.mjs#L1-20
standard({
  pluginFolder: "src/spores", // optional override
  pluginLoad: [
    "design",
    "themes",
    "lab",
    "content",
    "robots",
    "headers",
    "manifest",
    "sitemap",
  ],
});
```

## Philosophy

- Vertical slice: keep plugins self-contained.
- Zero shims: no legacy flags (`design`, `theme`, `lab`)—everything is a plugin.
- Performance and clarity: small, explicit manifests; no hidden magic.