@glowing-fishstick/shared

v0.1.5

Published

Shared server factory, lifecycle hooks, JWT, and admin middleware for glowing-fishstick

Readme

@glowing-fishstick/shared

Shared compatibility layer and curated public API for the glowing-fishstick framework.

Overview

This package contains shared code, utilities, and type definitions used by the core application module and other packages in the glowing-fishstick ecosystem. It also acts as the primary compatibility/public import boundary for logger utilities.

Usage

Install via npm (when published):

npm install @glowing-fishstick/shared

Import shared utilities in your module:

import { someUtility } from '@glowing-fishstick/shared';

Exports

All public exports from @glowing-fishstick/shared:

Server & Lifecycle

| Export | Description | |---|---| | createServer(app, config) | HTTP server factory with graceful shutdown and lifecycle hooks | | createHookRegistry() | Generic hook registry for sequential async lifecycle execution (FIFO) | | storeRegistries(app, startup, shutdown) | WeakMap-based private storage for app lifecycle registries | | attachHookRegistries(app) | Create and attach startup/shutdown registries + register methods to an Express app | | createShutdownGate(app) | Middleware that rejects new requests with 503 during graceful shutdown |

Logging (re-exported from @glowing-fishstick/logger)

| Export | Description | |---|---| | createLogger(options?) | Pino logger factory — pretty-printed in dev, JSON in prod | | createRequestLogger(logger, options?) | Express middleware for structured HTTP request/response logging |

Request & Middleware

| Export | Description | |---|---| | createRequestIdMiddleware() | Generates UUID per request (or uses x-request-id header) | | createAdminThrottle({ windowMs, max, paths }) | Fixed-window rate-limiting middleware for expensive routes |

Error Utilities

| Export | Description | |---|---| | normalizeError(err) | Normalize a thrown error into { statusCode, code, message } | | resolveErrorLogger(req) | Resolve logger from Express request context (falls back to console.error) | | logUnexpectedError(req, err, logFn, label?) | Log non-operational errors with request context |

Authentication (JWT)

| Export | Description | |---|---| | generateToken(secret, expiresIn?) | Generate a signed JWT token for service-to-service auth | | verifyToken(token, secret) | Verify and decode a JWT token | | jwtAuthMiddleware(secret) | Express middleware that validates bearer JWT tokens |

Dependency Injection

| Export | Description | |---|---| | createServiceContainer(options?) | Lightweight DI container with singleton/transient lifecycles and LIFO disposal | | ServiceAlreadyRegisteredError | Thrown when registering a duplicate service name | | ServiceNotFoundError | Thrown when resolving an unregistered service | | ServiceCircularDependencyError | Thrown when circular dependencies are detected during resolution | | ServiceResolutionError | Thrown when a provider function fails during resolution | | ServiceDisposeError | Thrown when a single service disposer fails | | ServiceAggregateDisposeError | Thrown when multiple service disposers fail during dispose() |

Formatting

| Export | Description | |---|---| | formatUptime(seconds) | Format seconds into human-readable uptime string (e.g., "5m 23s") |

Server Factory

import { createServer } from '@glowing-fishstick/shared';

When consuming via @glowing-fishstick/app, createServer is re-exported for convenience.

Logger

The package provides a Pino-based logger factory with environment-aware formatting:

@glowing-fishstick/shared is the recommended consumer import point for logger APIs. Implementation ownership is in @glowing-fishstick/logger.

import { createLogger } from '@glowing-fishstick/shared';

// Create logger with defaults
const logger = createLogger({ name: 'my-service' });

logger.info('Server starting');
logger.error({ err: new Error('failure') }, 'Operation failed');

Features

  • Development mode (NODE_ENV=development):

    • Pretty-printed console output (colorized, human-readable)
    • JSON logs written to ./logs/<name>.log
    • Automatic logs directory creation
  • Production mode:

    • JSON-formatted logs to stdout for container log collection
    • No file logging (relies on external log aggregation)

Configuration

const logger = createLogger({
  name: 'my-app', // Logger name (default: 'app')
  logLevel: 'debug', // Min level: trace|debug|info|warn|error|fatal (default: 'info')
  logDir: './logs', // Log directory (default: process.cwd()/logs)
  enableFile: true, // Enable file logging in dev (default: true)
});

HTTP Request Middleware

Optional middleware for logging HTTP requests and responses:

import { createLogger, createRequestLogger } from '@glowing-fishstick/shared';

const logger = createLogger({ name: 'http' });
app.use(createRequestLogger(logger));

Logs include: method, pathname, status code, duration, and request ID.

Request ID Middleware

Automatic request ID generation for distributed tracing:

import { createRequestIdMiddleware } from '@glowing-fishstick/shared';

// Generates unique UUID for each request (or uses x-request-id header)
app.use(createRequestIdMiddleware());

Built-in: Request ID generation is automatically enabled in createApp(), and request logging is enabled by default. To disable:

const config = createConfig({
  enableRequestLogging: false, // Disable HTTP logging
  logger,
});

Service Container

import { createServiceContainer } from '@glowing-fishstick/shared';

const services = createServiceContainer({ logger });

services.register('db', async (ctx) => {
  return await createPool(connectionString);
}, { dispose: (pool) => pool.close() });

const db = await services.resolve('db');

Note: Both createConfig() (@glowing-fishstick/app) and createApiConfig() (@glowing-fishstick/api) automatically create a ServiceContainer at config.services. Prefer using that container over creating your own.

Documentation

See the main glowing-fishstick documentation for usage examples and details.

License

MIT