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/.

معلومات المصدر

المستودع
stacksjs/stacks
آخر نشاط في المصدر
٣٠ سبتمبر ٢٠٢٦ في ٠٢:٢٦
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦٣١
التفرعات
٢٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
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() entry point — HTTP + WebSocket + job 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 v0.70.23 ├── 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 runtime server uses `Bun.serve()` directly. It handles two modes based on environment variables: ### HTTP Server Mode (default) ```typescript import type { Server, ServerWebSocket } from 'bun' const server = Bun.serve({ port: Number(process.env.PORT) || 3000, development: process.env.APP_ENV?.toLowerCase() !== 'production', async fetch(request: Request, server: Server<any>): Promise<Response | undefined> { // Attempt WebSocket upgrade first if (server.upgrade(request)) return // Delegate to the Stacks router return serverResponse(request) }, websocket: { open(_ws: ServerWebSocket): void {}, message(_ws: ServerWebSocket, _message: string): void {}, close(_ws: ServerWebSocket, _code: number, _reason?: string): void {}, }, }) ``` Key details: - `serverResponse()` is imported from `@stacksjs/router` and handles all route matching, middleware, and response generation - WebSocket upgrade is attempted before HTTP routing - `development` mode is enabled when `APP_ENV` is not `production` or `prod` - SIGINT handler gracefully exits the process ### Queue Worker Mode When `QUEUE_WORKER` env var is set, the same entry point runs a single job instead of starting the HTTP server: ```typescript if (process.env.QUEUE_WORKER) { const jobName = process.env.JOB.replace(/\.ts$/, '').replace(/[^a-zA-Z0-9_-]/g, '') const jobModule = await import(`./app/Jobs/${jobName}`) await retry(() => jobModule.default.handle(), { backoffFactor: Number(process.env.JOB_BACKOFF_FACTOR) || 2, retries: Number(process.env.JOB_RETRIES) || 3, initialDelay: Number(process.env.JOB_INITIAL_DELAY) || 1000, jitter: process.env.JOB_JITTER === 'true', }) process.exit(0) } ``` Environment variables for job execution: - `QUEUE_WORKER` -- enables worker mode (any truthy value) - `JOB` -- job file name (e.g., `SendEmail.ts`), sanitized to prevent path traversal - `JOB_RETRIES` -- retry count (default: 3) - `JOB_BACKOFF_FACTOR` -- exponential backoff multiplier (default: 2) - `JOB_INITIAL_DELAY` -- initial retry delay in ms (default: 1000) - `JOB_JITTER` -- enable jitter on retries (`'true'` to enable) ## 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) Entry point for compiled production binaries. Sequence: 1. Sets `__STACKS_BINARY_MODE__ = true` on `globalThis` (prevents auto-registration in routes) 2. Sets `SKIP_CONFIG_LOADING = 'true'` env var 3. Imports `loadRoutes` and `serve` from `@stacksjs/router` 4. Loads routes from the `app/Routes.ts` registry via `loadRoutes(routeRegistry)` 5. Loads ORM auto-generated routes from `../../orm/routes` (model CRUD endpoints) 6. Calls `serve({ port, host })` to start the Bun HTTP server ```typescript // Production startup flow loadRoutes(routeRegistry) .then(async () => { await import('../../orm/routes') // ORM auto-routes (after manual routes) serve({ port: config.server.port, host: config.server.host }) }) ``` ## 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` - ESLint config: `storage/framework/server-auto-imports.json` - Runtime index files: `storage/framework/auto-imports/` (see below) ### generateAutoImportFiles() ```typescript async function generateAutoImportFiles(): Promise<void> ``` 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: any, status?: number): ResponseData // default status: 200 protected success(data: any): ResponseData // alias for json(data, 200) protected created(data: any): ResponseData // json(data, 201) protected noContent(): any // response.noContent() protected error(message: string, status?: number): ResponseData // json({ error }, 500) protected notFound(message?: string): ResponseData // error(msg, 404) protected unauthorized(message?: string): ResponseData // error(msg, 401) protected forbidden(message?: string): ResponseData // error(msg, 403) protected validate(request: Request, rules: Record<string, any>): 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
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub