@signmax/remix-base
v0.0.4
Published
Server and shared utils for React Router 7 projects
Maintainers
Readme
@signmax/remix-base
Production-ready server and shared utilities for React Router 7 apps.
@signmax/remix-base bundles an opinionated Express 5 setup, middleware suite, instrumentation, and utilities so you
can ship React Router (Remix) projects without re-writing the same server glue.
Quick Start
npm install @signmax/remix-baseimport { serveApp } from "@signmax/remix-base/server"
import type { ServerBuild } from "react-router"
const build = () => import("./build/server/index.js") as Promise<ServerBuild>
await serveApp(build, {})What You Get
- Express 5 server with sensible defaults and CloudFront-aware proxy trust
- Middleware bundle (Helmet, CSP, no-index, trailing slash guard, Sentry IP) plus optional device-key helper
- Structured logging via Pino and Prometheus metrics endpoint
- GraphQL helpers with cookie pass-through and shared-secret auth
- Load context utilities, GrowthBook integration, and AWS Secrets Manager helper
- TypeScript-first API with comprehensive tests
Server Setup
Switch to the options object when you need control over middleware, dev servers, or context creation:
import { serveApp, type ServeAppOptions } from "@signmax/remix-base/server"
import { getLoadContext } from "@signmax/remix-base/load_context"
import { deviceKeyMiddleware, requestMiddleware } from "@signmax/remix-base/middleware"
const build = async () => import("../build/server/index.js")
const options: ServeAppOptions = {
middleware: [requestMiddleware(), deviceKeyMiddleware({ cookieName: "device_id" })],
getLoadContext: (req, res) => getLoadContext(req, res, { deviceKeyCookieName: "device_id" }),
trustCloudFrontIPs: true,
}
await serveApp(build, options)In development, pass a Vite dev server (devServer: viteServer.middlewares) and call startMetrics() when you want a
Prometheus endpoint.
Middleware & Utilities
import {
cspMiddleware,
deviceKeyMiddleware,
endingSlashMiddleware,
helmetMiddleware,
noIndexMiddleware,
requestMiddleware,
sentryIPMiddleware,
} from "@signmax/remix-base/middleware"
import {
BrowserDetection,
pipeHeaders,
getConservativeCacheControl,
makeTimings,
time,
getRevision,
} from "@signmax/remix-base/util"CSP middleware ships with nonce support; call
createCspMiddlewarefor custom policies.requestMiddlewareis a factory that accepts GraphQL client options and returns middleware that attaches a GraphQL request helper toreq.request:import { requestMiddleware } from "@signmax/remix-base/middleware" const customRequestMiddleware = requestMiddleware({ endpoint: "https://api.example.com/graphql", sharedSecret: process.env.SHARED_SECRET, sharedSecretHeader: "x-api-key", passthroughHeaders: ["x-tenant-id"], skipCookies: false, }) // Or use with default options const defaultRequestMiddleware = requestMiddleware()Utility exports cover HTTP headers, server timing, revision lookup, and user-agent parsing helpers.
Logging & Metrics
import logger from "@signmax/remix-base/logger"
import { startMetrics } from "@signmax/remix-base/metrics"
logger.info("Application started")
const metrics = await startMetrics({ port: 9394 })startMetrics spins up a dedicated Express app exposing /metrics and returns a handle so you can stop the server
during shutdown.
GraphQL Client
import { createClient, createRequest, createResponseMiddleware } from "@signmax/remix-base/client"
const gqlClient = createClient({
endpoint: "https://api.example.com/graphql",
sharedSecret: process.env.SHARED_SECRET,
})
const requestFn = createRequest(req, res, createResponseMiddleware(req, res), {
passthroughHeaders: ["x-tenant-id"],
})Set includeDefaultPassthroughHeaders to false when you want complete control over forwarded headers.
AWS Secrets Manager
import { loadSecrets } from "@signmax/remix-base/secrets"
const secrets = await loadSecrets<{ apiKey: string }>("my-app/production", {
region: "us-east-1",
})The region falls back to AWS_REGION or eu-central-1.
Optional Integrations
Sentry – call
initwhenSENTRY_DSNis set.import { init } from "@signmax/remix-base/instrumentation" if (process.env.SENTRY_DSN) { init({ dsn: process.env.SENTRY_DSN, configuration: { environment: "production", tracesSampleRate: 0.1, profilesSampleRate: 0.05, sendDefaultPii: false, }, }) }GrowthBook – install
@growthbook/growthbook+eventsourceand pass the instance viagetLoadContext.import { createGrowthBook } from "@signmax/remix-base/growthbook" import { getLoadContext } from "@signmax/remix-base/load_context" const growthbook = await createGrowthBook({ apiHost: "https://cdn.growthbook.io", clientKey: "key" }) const getContext = (req, res) => getLoadContext(req, res, { growthbook })
Environment Variables
NODE_ENV– sets development/production modePORT– HTTP port (4000by default)BUILD_DIR– static asset root (build/clientby default)ASSETS_DIR– fingerprinted assets directory (defaults to${BUILD_DIR}/assets)PROMETHEUS_EXPORTER_PORT– metrics server port (9394by default)AWS_REGION– Secrets Manager region (eu-central-1by default)GIT_REV– optional release/commit override for logging and Sentry
Testing Helpers
import { gqlOpHandler } from "@signmax/remix-base/test/helpers"MSW helpers simplify GraphQL mocking and reuse the package defaults.
Publishing
Releases are driven by GitHub Releases:
- Update the version in
package.jsonand refreshCHANGELOG.md. - Commit, push, and tag (
vX.Y.Z). - Create a GitHub Release; CI publishes to npm.
License
MIT
