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

@luckystack/server

v0.2.6

Published

One-call server bootstrap for LuckyStack: HTTP + Socket.io + framework routes (api, sync, _health, /auth, uploads) wired together. Consumer's server.ts shrinks to ~20 lines.

Readme

@luckystack/server

One-call server bootstrap for LuckyStack. HTTP + Socket.io + framework routes (/api/*, /sync/*, /_health, /_test/reset, /auth/*, /uploads/*) wired together. Your server.ts shrinks to ~20 lines.

Install

npm install @luckystack/server @luckystack/core @luckystack/api @luckystack/login @luckystack/sync @luckystack/presence socket.io

Quickstart — recommended (bootstrapLuckyStack)

bootstrapLuckyStack is a thin wrapper around createLuckyStackServer that auto-imports your luckystack/<pkg>/*.ts overlay files in topological order before listening, so registries (DI, hooks, providers) are populated by the time the HTTP server boots. This is what create-luckystack-app scaffolds.

import 'dotenv/config';
import '../config';            // your registerProjectConfig(...)
import '../deploy.config';     // your registerDeployConfig(...)
import '../services.config';   // your registerServicesConfig(...)

import { bootstrapLuckyStack } from '@luckystack/server';
import { serveFile, serveFavicon } from './prod/serveFile';

const server = await bootstrapLuckyStack({
  serveFile,
  serveFavicon,
});

await server.listen();

The bootstrap call runs (in order):

  1. Auto-imports luckystack/core/*.ts, luckystack/deploy/*.ts, luckystack/login/*.ts, luckystack/sentry/*.ts, luckystack/presence/*.ts, luckystack/docs-ui/*.ts, luckystack/server/*.ts (topologically sorted, then alphabetically inside each folder).
  2. Hands off to createLuckyStackServer(options).

Set skipOverlayLoad: true to handle every registration yourself, or overlayRoot: 'custom-folder' to load from somewhere other than ./luckystack.

Pre-flight check — verifyBootstrap

Call verifyBootstrap after the overlay loads (or after your manual registrations) and before server.listen() if you want to fail fast on missing registrations instead of silent runtime crashes:

import { bootstrapLuckyStack, verifyBootstrap } from '@luckystack/server';

const server = await bootstrapLuckyStack({ serveFile, serveFavicon });

await verifyBootstrap({
  requireDeployConfig: true,    // single-instance deploys can omit this
  requireServicesConfig: true,  // only true when the router will run
  requireOAuthProviders: true,  // false if you only use credentials login
});

await server.listen();

verifyBootstrap throws a single descriptive Error listing every missing registration. The full check covers:

  • ProjectConfig — always required.
  • DeployConfig — when requireDeployConfig: true.
  • ServicesConfig — when requireServicesConfig: true.
  • OAuth providers — when requireOAuthProviders: true and only the default credentials entry has been registered.
  • RuntimeMapsProvider — hard-fails in production; loud-warns in dev because devkit hot-reload normally registers one. Without it, every API/sync request silently resolves to notFound.
  • LocalizedNormalizer — hard-fails in production; warns in dev. Without it, error responses degrade to errorCode-as-message (no i18n).

Lower-level entry — createLuckyStackServer

Use this directly when you want to control the order of imports yourself or skip the overlay convention:

import { initializeSentry } from '@luckystack/error-tracking';
import { registerPresenceHooks } from '@luckystack/presence';
import { createLuckyStackServer } from '@luckystack/server';

initializeSentry();
registerPresenceHooks();

const server = await createLuckyStackServer({
  serveFile,
  serveFavicon,
});
await server.listen();

Both entries handle devkit hot reload + console init in dev mode automatically — opt out with enableDevTools: false if you have your own.

Options

interface CreateLuckyStackServerOptions {
  port?: number | string;          // default: process.env.SERVER_PORT ?? 80
  ip?: string;                     // default: process.env.SERVER_IP ?? '127.0.0.1'
  serveFile?: StaticFileHandler;   // catch-all for non-framework GETs (Vite output, SPA fallback)
  serveFavicon?: FaviconHandler;   // /favicon.ico
  customRoutes?: CustomRouteHandler; // pre-fallback hook; return true to mark handled
  enableDevTools?: boolean;        // default: NODE_ENV !== 'production'
  maxHttpBufferSize?: number;      // default: 5 MB
}

customRoutes runs before the static file serving, so you can add project-specific HTTP endpoints (webhooks, OG image generation, etc.) without forking the package. Return true if you ended the response.

You can also register custom routes globally via registerCustomRoute(handler) — the bootstrap call composes every registered handler into the running server. This is what @luckystack/docs-ui uses to mount /_docs.

import { registerCustomRoute } from '@luckystack/server';

registerCustomRoute(async (req, res) => {
  if (req.url !== '/healthz') return false;
  res.statusCode = 200;
  res.end('ok');
  return true;
});

What it wires

  • HTTP server with CORS + security headers, OPTIONS preflight, method validation, cookie sliding, CSRF middleware.
  • Socket.io server attached to the HTTP server, with optional Redis adapter when configured in deploy config.
  • Framework routes: /_health, /livez, /readyz, /_test/reset (dev/test only), /api/* and /sync/* (with SSE streaming), /auth/api, /auth/callback/*, /uploads/*, /assets/*, /csrf-token.
  • Presence broadcasting (when enabled in project config): connect / disconnect / reconnect, location updates, peer notifications.
  • Boot UUID written on startup so the load-balancer (@luckystack/router) can detect rolling restarts.
  • Dev tools in non-production: devkit hot reload, console initializer.

HTTP route handler layout

handleHttpRequest is now a thin (~190-line) orchestrator that sets up CORS / origin / security headers, runs the CSRF middleware, then dispatches a route-handler table. Each handler matches its own route path and returns boolean (handled or not). The handlers live in packages/server/src/httpRoutes/:

| File | Routes | | --- | --- | | csrfMiddleware.ts + csrfRoute.ts | CSRF guard on writes + GET /csrf-token | | healthRoutes.ts | /livez, /readyz, /_health | | testResetRoute.ts | /_test/reset (dev/test only — see Security below) | | faviconRoute.ts | /favicon.ico | | uploadsRoute.ts | /uploads/* (avatar serving via serveAvatar) | | authApiRoute.ts | /auth/api/* | | authCallbackRoute.ts | /auth/callback/* | | apiRoute.ts | /api/* (delegates to @luckystack/api's handleHttpApiRequest) | | syncRoute.ts | /sync/* (delegates to @luckystack/sync's handleHttpSyncRequest) | | customRoutes.ts | Calls every handler registered via registerCustomRoute(...) and the inline customRoutes option | | staticRoutes.ts | Final fallback to the consumer's serveFile(...) (Vite SPA, etc.) |

Top-level handleHttpRequest + dispatchRoutes(handlers, ctx) are the only orchestration; everything else is a flat list of single-purpose handlers. SSE handling, error fall-through, and dispatch order are preserved.

Security defaults that may surprise you

  • CORS fail-closed. If neither Origin nor Referer is present, only read-only methods (GET, HEAD, OPTIONS) are allowed; state-changing methods are rejected with 403. Earlier builds fell back to Host, which silently bypassed CORS for non-browser callers (curl, server-to-server). When you curl a write endpoint, set -H 'Origin: https://your-allowed-origin'.
  • /_test/reset is fail-closed. It requires both NODE_ENV to be exactly development or test AND a non-empty TEST_RESET_TOKEN env var. Any other state returns 403 (no silent allow-list). Wire TEST_RESET_TOKEN in your dev/test .env.local and pass it as the x-test-reset-token: ${TOKEN} header on the reset call. @luckystack/test-runner's resetServerState reads the same env var.
  • CSRF middleware. Writes to /api/* and /sync/* require an x-csrf-token header that matches the value minted on the session record (mirrored via GET /auth/csrf). The apiRequest helper in @luckystack/core/client attaches it automatically. Rejections dispatch the csrfMismatch hook before returning 403; the payload contains presence-only token info, never the value. The header name, token length, and cookie options are customisable via registerCsrfConfig({ headerName, tokenLength, cookieOptions }) from @luckystack/core — see packages/core/docs/csrf-config.md.

Public API

| Export | Purpose | | --- | --- | | bootstrapLuckyStack(options) | High-level entry: verifies config, auto-imports overlay, then calls createLuckyStackServer. | | createLuckyStackServer(options) | Lower-level factory that returns { httpServer, ioServer, listen }. | | verifyBootstrap(requirements?) | Pre-flight check for project/deploy/services config and required env keys. | | registerCustomRoute(handler) / getCustomRoutes() / clearCustomRoutes() | Global custom-route registry composed by bootstrapLuckyStack. | | Hook payload types: OnSocketConnectPayload, OnSocketDisconnectPayload, PreRoomJoinPayload, PostRoomJoinPayload, PreRoomLeavePayload, PostRoomLeavePayload, OnLocationUpdatePayload | For socket-lifecycle hook handlers. | | Types: CreateLuckyStackServerOptions, BootstrapLuckyStackOptions, BootstrapRequirements, RunningLuckyStackServer, RouteContext, StaticFileHandler, FaviconHandler, CustomRouteHandler | Handler typing. |

Dependencies

  • Runtime: @luckystack/api, @luckystack/core, @luckystack/login, @luckystack/presence, @luckystack/sync
  • Peer (canonical ranges, standardized 2026-05-07):
    • @prisma/client@^6.19.0 (transitively required via @luckystack/core)
    • socket.io@^4.8.0
  • Optional peer: @luckystack/error-tracking, @luckystack/email, @luckystack/docs-ui — bootstrap auto-detects them but does not require them.

Selecting bundles + port at runtime

@luckystack/server/parseArgv is a side-effect-only entrypoint. Import it as the first line of your server.ts so positional CLI args are parsed before any module that reads process.env.SERVER_PORT at load time (notably your project's config.ts).

// server.ts
import '@luckystack/server/parseArgv';
// ...rest of your bootstrap

Argv shape: <bundle[,bundle...]> [port]

npm run server                              # default preset, port 80
npm run server -- billing                   # one bundle, port 80
npm run server -- billing,vehicles 4001     # merge bundles, listen on 4001

When multiple presets are passed, the framework loads each preset's generated route map and shallow-merges apis / syncs / functions. Key collisions across presets throw at boot (services must own exactly one preset).

Related architecture docs

License

MIT — see LICENSE.