JSPM

  • Created
  • Published
  • Downloads 538
  • Score
    100M100P100Q110717F
  • License MIT

Server and shared utils for React Router 7 projects

Package Exports

  • @signmax/remix-base
  • @signmax/remix-base/client
  • @signmax/remix-base/growthbook
  • @signmax/remix-base/instrumentation
  • @signmax/remix-base/logger
  • @signmax/remix-base/metrics
  • @signmax/remix-base/middleware
  • @signmax/remix-base/router_context
  • @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-base
import { 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 createCspMiddleware for custom policies.

  • requestMiddleware is a factory that accepts GraphQL client options and returns middleware that attaches a GraphQL request helper to req.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 init when SENTRY_DSN is 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 + eventsource and pass the instance via getLoadContext.

    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 mode
  • PORT – HTTP port (4000 by default)
  • BUILD_DIR – static asset root (build/client by default)
  • ASSETS_DIR – fingerprinted assets directory (defaults to ${BUILD_DIR}/assets)
  • PROMETHEUS_EXPORTER_PORT – metrics server port (9394 by default)
  • AWS_REGION – Secrets Manager region (eu-central-1 by 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:

  1. Update the version in package.json and refresh CHANGELOG.md.
  2. Commit, push, and tag (vX.Y.Z).
  3. Create a GitHub Release; CI publishes to npm.

License

MIT