Skip to main content

stacks-server

Use when working with the Stacks development or production server - server configuration, server middleware, or server startup. Covers @stacksjs/server and storage/framework/server/.

Datos de origen

Repositorio
stacksjs/stacks
Última actividad en el origen
17 de octubre de 2026 a las 16:13
Idioma detectado de SKILL.md
inglés
Estrellas
633
Forks
20

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
stacks-server
description
Use when working with the Stacks development or production server - server configuration, server middleware, or server startup. Covers @stacksjs/server and storage/framework/server/.
license
MIT
compatibility
Bun >= 1.3.0, TypeScript
allowed-tools
Read Edit Write Bash Grep Glob
# Stacks Server ## Key Paths - Core package: `storage/framework/core/server/src/` (published as `@stacksjs/server`) - Server runtime: `storage/framework/server/` (the actual Bun HTTP server + Docker build) - Server types: `storage/framework/core/types/src/server.ts` - Ports types: `storage/framework/core/types/src/ports.ts` - Package (core): `storage/framework/core/server/package.json` - Package (runtime): `storage/framework/server/package.json` ## Source Files ``` core/server/src/ ├── index.ts # Re-exports: config, controllers/base, imports, maintenance ├── config.ts # config() factory - maps ServerOptions.type to host/port ├── config-production.ts # Minimal env-based config for compiled production binaries ├── imports.ts # Auto-import system: scan models/jobs/controllers, register bun plugin ├── maintenance.ts # Laravel-like maintenance mode (down/up/bypass) └── controllers/ └── base.ts # Base Controller class with json/success/error helpers server/ ├── src/ │ ├── index.ts # Bun.serve() HTTP entry and one-shot queue worker │ └── utils.ts # Docker build helpers (cleanCopy, buildDockerImage, useCustomOrDefaultServerConfig) ├── build.ts # Full build pipeline: bundle server + app, post-process, optionally build Docker ├── dev # Shell script for local/remote Docker dev (mounts volumes) ├── Dockerfile # Multi-stage Bun Docker image (oven/bun:1.3.10) ├── package.json # stacks-server package ├── tsconfig.json # Extends core tsconfig ├── tsconfig.docker.json # Docker-specific tsconfig with path aliases ├── .dockerignore # Excludes Dockerfile, .git, node_modules, etc. └── .gitignore # Excludes app/, config/, dist/, storage/ (build artifacts) ``` ## Server Entry Point (server/src/index.ts) The HTTP runtime delegates fetch requests to serverResponse from `@stacksjs/router/runtime`. It has no WebSocket upgrade handlers. Realtime clients connect to the separate authenticated broadcast server described by `stacks-realtime`. PORT defaults to 3000; APP_ENV production/prod disables development mode. Production enables reusePort for replacement instances on supported platforms. SIGTERM stops accepting connections and drains in-flight requests, with a SHUTDOWN_GRACE_MS deadline (default fifteen seconds). Supervisors still own restart and deploy health-gating policy. With QUEUE_WORKER set, this entry instead loads the sanitized JOB file and runs its handle with retry. JOB_RETRIES, JOB_BACKOFF_FACTOR, JOB_INITIAL_DELAY and JOB_JITTER configure that one-shot mode. It is distinct from the durable `buddy queue:work` processor. ## Server Config (core/server/src/config.ts) ```typescript function config(options: ServerOptions): { host: string, port: number, open: boolean } ``` Maps a `ServerOptions.type` to a host/port pair using the `ports` config object. Supported types: | Type | Port Source | |---------------|---------------------| | `frontend` | `ports.frontend` | | `backend` | `ports.backend` | | `api` | `ports.api` | | `admin` | `ports.admin` | | `library` | `ports.library` | | `desktop` | `ports.desktop` | | `docs` | `ports.docs` | | `email` | `ports.email` | | `inspect` | `ports.inspect` | | `system-tray` | `ports.systemTray` | | `database` | `ports.database` | All types resolve to `host: 'localhost'`. If no type is provided or it doesn't match, falls back to `host: options.host || 'stacks.localhost'` and `port: options.port || 3000`. ### ServerOptions Type ```typescript interface ServerOptions { type?: 'frontend' | 'backend' | 'api' | 'library' | 'desktop' | 'docs' | 'email' | 'admin' | 'system-tray' | 'database' host?: string port?: number open?: boolean } ``` ### Ports Interface ```typescript interface Ports { frontend: number backend: number // proxies api admin: number library: number desktop: number email: number docs: number inspect: number api: number // the bun server systemTray: number database: number // i.e. DynamoDB local } ``` ## Production Config (core/server/src/config-production.ts) Minimal config for compiled binaries -- no runtime file loading, all env-based: ```typescript const config = { app: { name: process.env.APP_NAME || 'Stacks', env: process.env.APP_ENV || 'production', debug: process.env.APP_DEBUG === 'true' || false, url: process.env.APP_URL || 'https://stacksjs.com', }, server: { port: Number(process.env.PORT) || 3000, host: '0.0.0.0', }, logging: { level: process.env.LOG_LEVEL || 'info', }, } ``` Used by `start.ts` (the production binary entry point) with `SKIP_CONFIG_LOADING=true` to bypass dynamic config imports. ## Production Start (core/server/src/start.ts) The compiled-binary entry marks binary mode and disables external runtime config loading. It reads appRouteRegistry at runtime, loads manual routes first, then tries `@stacksjs/orm/routes` with a checkout-relative fallback. Missing ORM routes warn; unresolved registered route middleware aborts startup rather than serving an unguarded route. Bun receives `hostname`, not a host option. Unhandled rejections reach the shared report hook; uncaught exceptions report, flush logging and exit so a supervisor can restart. This entry's startup contract differs from the Docker HTTP entry and the STX production views server; inspect the selected build/deploy entrypoint before copying environment assumptions. ## Auto-Imports System (core/server/src/imports.ts) ### initiateImports() ```typescript function initiateImports(): void ``` Registers a Bun bundler plugin (`bun-plugin-auto-imports`) that makes models, jobs, controllers, and resource functions available globally without explicit imports. Scan order (user overrides framework overrides defaults): - **Models**: `app/Models/` > `storage/framework/defaults/app/Models/` > `storage/framework/defaults/app/Models/` - **Jobs**: `app/Jobs/` - **Controllers**: `app/Controllers/` > `storage/framework/defaults/app/Controllers/` - **Functions**: `resources/functions/` Outputs: - `.d.ts` file: `storage/framework/types/server-auto-imports.d.ts` - Compatibility manifest: storage/framework/server-auto-imports.json; lint remains pickier - Runtime index files: `storage/framework/auto-imports/` (see below) ### generateAutoImportFiles() ```typescript async function generateAutoImportFiles(): Promise<void> ``` Package-based apps address framework defaults through `@stacksjs/defaults` exports, preserving application overrides. Generated imports never depend on the physical npm or Pantry installation path. An app created with `--with-core` keeps source-relative defaults imports; detection uses the framework source layout, independently of the application's package name. Generates runtime-importable index files under `storage/framework/auto-imports/`: - `functions.ts` -- re-exports from `resources/functions/` - `models.ts` -- re-exports default exports from model definition files as named exports - `jobs.ts` -- re-exports default exports from job definition files - `controllers.ts` -- re-exports default exports from controller definition files - `index.ts` -- combined re-export of all above - `globals.ts` -- script that assigns all exports to `globalThis` ### injectGlobalAutoImports() ```typescript async function injectGlobalAutoImports(): Promise<void> ``` Dynamically imports `storage/framework/auto-imports/index.ts` and assigns all exports to `globalThis`. Call this early in application startup to make models available globally (e.g., `Post.where('title', 'test')` without imports). ### scanDefineModelExports(dir: string): ExportInfo[] Internal helper that scans a directory for `.ts` files (excluding `.d.ts`, `index.ts`, `README*`) and returns file names as export info. Used for models, jobs, and controllers that use `export default defineModel(...)` pattern. ## Base Controller (core/server/src/controllers/base.ts) ```typescript class Controller { protected json(data: unknown, status?: ResponseStatus): Response // default status: 200 protected success(data: unknown): Response // alias for json(data, 200) protected created(data: unknown): Response // json(data, 201) protected noContent(): any // response.noContent() protected error(message: string, status?: ResponseStatus): Response // json({ error }, 500) protected notFound(message?: string): Response // error(msg, 404) protected unauthorized(message?: string): Response // error(msg, 401) protected forbidden(message?: string): Response // error(msg, 403) protected validate(request: Request, rules: Record<string, unknown>): Promise<void> } ``` Usage: ```typescript import { Controller } from '@stacksjs/server' class UserController extends Controller { async index() { const users = await User.all() return this.success(users) } async store(request: Request) { await this.validate(request, { name: 'required', email: 'required|email' }) const user = await User.create(request.body) return this.created(user) } async show(id: number) { const user = await User.find(id) if (!user) return this.notFound('User not found') return this.success(user) } } ``` ## Maintenance Mode (core/server/src/maintenance.ts) Laravel-like maintenance mode that writes/removes a `storage/framework/down` file. ### Core Functions ```typescript async function down(options?: Partial<MaintenancePayload>): Promise<void> async function up(): Promise<void> async function isDownForMaintenance(): Promise<boolean> async function maintenancePayload(): Promise<MaintenancePayload | null> ``` ### MaintenancePayload ```typescript interface MaintenancePayload { time: number // When maintenance was activated (Date.now()) message?: string // Display message (default: 'We are currently performing maintenance...') retry?: number // Retry-After header value in seconds secret?: string // Bypass token allowed?: string[] // Allowed IP addresses status?: number // HTTP status (default: 503) template?: string // Custom template path redirect?: string // Redirect URL instead of showing maintenance page } ``` ### Bypass Helpers ```typescript function isAllowedIp(ip: string, allowed?: string[]): boolean // Localhost IPs ('127.0.0.1', '::1', 'localhost') are always allowed function hasValidBypassCookie(cookies: Record<string, string>, secret: string): boolean // Checks for cookie: stacks_maintenance_bypass=<secret> function isSecretPath(path: string, secret: string): boolean // Matches /<secret> or /<secret>/... function bypassCookieValue(secret: string): string // Returns: 'stacks_maintenance_bypass=<secret>; Path=/; HttpOnly; SameSite=Lax' ``` ### Response Helpers ```typescript function maintenanceHtml(payload: MaintenancePayload): string // Returns a styled HTML page with gradient background function maintenanceResponse(payload: MaintenancePayload): Response // Returns Response with correct status, Retry-After header, or 302 redirect ``` ### Usage ```typescript import { down, up, isDownForMaintenance } from '@stacksjs/server' // Put app in maintenance mode with bypass secret await down({ secret: 'my-bypass-token', retry: 300 }) // Check if in maintenance if (await isDownForMaintenance()) { const payload = await maintenancePayload() // ... } // Bring app back up await up() ``` ## Sitemap and robots.txt (core/actions/src/seo.ts) The views server answers `/sitemap.xml` and `/robots.txt` for every app, generated from `resources/views` at request time. `buddy dev` (`core/actions/src/dev/views.ts`) and `buddy serve` (`core/buddy/src/production-server.ts`) call the same `createSiteSeoHandler()` at the same point in `onRequest` (after redirects and rewrites), so dev and production answer identically. No route, no build step, no app code. Do not add `route.get('/sitemap.xml')` to `routes/`: the views server does not forward root GETs to the API. - **Listed**: every static route under `resources/views`, with `lastmod` from the file, plus the blog's published posts (`content/blog`, or a CMS-built `dist/blog/sitemap.xml`) merged into the same file. `/blog/sitemap.xml` is still served too. - **Not listed**: dynamic routes (`[slug].stx`), error and holding pages (`404`, `errors/*`, `coming-soon`), `components/`, `layouts/`, `partials/`, `emails/`, `_`-prefixed files, pages behind `definePageMeta({ middleware: ['auth'] })`, paths in `seo.sitemap.exclude`, paths robots.txt disallows, and any page that says **noindex**. The framework's default views (`/login`, ...) are never listed. - **noindex**, the one signal, read from the page source: `<meta name="robots" content="noindex">`, `robots: 'noindex'` in a head object, or `const noindex = true` in the server script (the flag a shared head partial turns into the tag - the scan cannot follow an `@include`, so spell it that way). `definePageMeta({ sitemap: false })` also keeps a page out. - **robots.txt**: `User-agent: *`, `Allow: /`, `Disallow: /api/` plus `seo.robots.disallow`, extra groups from `seo.robots.rules`, and `Sitemap: <origin>/sitemap.xml`. Never disallow a page just to hide it: a crawler that cannot fetch it never sees its noindex.
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub