Package Exports
- @signmax/remix-base
- @signmax/remix-base/client
- @signmax/remix-base/growthbook
- @signmax/remix-base/instrumentation
- @signmax/remix-base/load_context
- @signmax/remix-base/logger
- @signmax/remix-base/metrics
- @signmax/remix-base/middleware
- @signmax/remix-base/secrets
- @signmax/remix-base/server
- @signmax/remix-base/test/helpers
- @signmax/remix-base/util
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 = {
build,
middleware: [requestMiddleware, deviceKeyMiddleware],
getLoadContext: (req, res) => getLoadContext(req, res, { deviceKeyCookieName: "device_id" }),
enableCloudFrontIpUpdater: true,
}
await serveApp(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. requestMiddlewareattaches a GraphQL request helper toreq.request.- 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 }>({
secretName: "my-app/production",
region: "us-east-1",
})Defaults read AWS_SECRET_NAME, AWS_REGION, and fall back to app/env/${APP_ENV} in eu-central-1.
Optional Integrations
Sentry – call
initwhenSENTRY_DSNis set.import { init } from "@signmax/remix-base/instrumentation" if (process.env.SENTRY_DSN) { init({ denyUrls: [/\/health/, /\/metrics/], tracesSampleRate: 0.1 }) }
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 modeAPP_ENV– logical environment label for telemetry and secrets (defaults toNODE_ENV)PORT– 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)SENTRY_DSN– enables Sentry instrumentation when definedAWS_SECRET_NAME– Secrets Manager name (defaults toapp/env/${APP_ENV})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