Catalog npm
Back to packageRELEASE DETAILS

1.19.2

npm

90dc-core

Shared utilities, models, and middleware for 90 Day Challenge microservices.

Published31 Mar 2026
Direct dependencies42
Transitive dependenciesNot calculated

README

Current package documentation

90dc-core

Shared utilities, models, and middleware for 90 Day Challenge microservices.

Version 1.11.0 - NEW Features ✨

This version adds configuration validation and error handling middleware to improve code quality across all services.

What's New

  • ✅ Type-safe configuration with Zod validation
  • ✅ Consistent error handling across all services
  • ✅ Request validation middleware with Zod
  • ✅ Comprehensive error classes (404, 400, 401, 403, 500, etc.)
  • ✅ Fail-fast validation on startup

Installation

npm install 90dc-core@latest zod

Quick Start

1. Configuration Validation

import { BaseConfigSchema, ConfigValidator } from '90dc-core';
import { z } from 'zod';

// Extend base config with service-specific settings
const ConfigSchema = BaseConfigSchema.extend({
  GOOGLE_CLIENT_ID: z.string().min(1),
  APPLE_TEAM_ID: z.string().min(1),
  MOLLIE_API_KEY: z.string().min(1)
});

// Create validated config (fails fast on startup if invalid)
const config = new ConfigValidator(ConfigSchema);

// Use with type safety
const port = config.get('PORT'); // Type: number
const jwtSecret = config.get('JWT_SECRET'); // Type: string
const googleClientId = config.get('GOOGLE_CLIENT_ID'); // Type: string

2. Error Handling Middleware

import Koa from 'koa';
import { createErrorMiddleware } from '90dc-core';

const app = new Koa();

// Add error middleware FIRST
app.use(createErrorMiddleware({
  exposeErrorDetails: config.isDevelopment()
}));

// Add your routes
app.use(router.routes());

3. Throwing Errors

import {
  NotFoundError,
  ValidationError,
  ForbiddenError,
  AuthenticationError
} from '90dc-core';

class UserController {
  async getUser(ctx: Context) {
    const user = await User.findByPk(ctx.params.id);

    if (!user) {
      throw new NotFoundError('User'); // Returns 404 with consistent format
    }

    ctx.body = { user };
  }

  async createUser(ctx: Context) {
    const existing = await User.findOne({ where: { email } });

    if (existing) {
      throw new ConflictError('Email already registered'); // Returns 409
    }

    // ... create user
  }
}

4. Request Validation

import { validateRequest } from '90dc-core';
import { z } from 'zod';

const CreateUserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  firstName: z.string().min(1).max(100)
});

router.post('/users',
  validateRequest({ body: CreateUserSchema }),
  async (ctx) => {
    // ctx.request.body is now validated and typed
    const user = await User.create(ctx.request.body);
    ctx.body = { user };
  }
);

Error Response Format

All errors return consistent JSON:

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "User not found"
  }
}

With details for validation errors:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {
      "validationErrors": [
        {
          "path": "email",
          "message": "Invalid email",
          "code": "invalid_string"
        }
      ]
    }
  }
}

Available Error Types

import {
  ValidationError,         // 400 - Invalid data
  AuthenticationError,     // 401 - Not authenticated
  ForbiddenError,          // 403 - No permission
  NotFoundError,           // 404 - Resource not found
  ConflictError,           // 409 - Resource conflict
  UnprocessableEntityError,// 422 - Semantic error
  RateLimitError,          // 429 - Too many requests
  InternalServerError,     // 500 - Server error
  ServiceUnavailableError, // 503 - Service down
  DatabaseError,           // 500 - Database issue
  ExternalAPIError,        // 502 - External API failed
} from '90dc-core';

Common Config Schemas

Reusable schemas for common configurations:

import { CommonSchemas } from '90dc-core';

const ConfigSchema = BaseConfigSchema
  .extend(CommonSchemas.redis.shape)
  .extend(CommonSchemas.jwt.shape)
  .extend(CommonSchemas.googleOAuth.shape);

Available common schemas:

  • CommonSchemas.database - PostgreSQL configuration
  • CommonSchemas.redis - Redis configuration
  • CommonSchemas.jwt - JWT authentication
  • CommonSchemas.googleOAuth - Google OAuth
  • CommonSchemas.appleOAuth - Apple OAuth
  • CommonSchemas.serviceUrls - Inter-service URLs
  • CommonSchemas.featureFlags - Feature flags

Full Documentation

See USAGE_EXAMPLES.md for:

  • Complete usage examples
  • Migration guide from old code
  • Best practices
  • Testing examples
  • All available features

Exports

Configuration

import {
  ConfigValidator,
  BaseConfigSchema,
  CommonSchemas,
  createConfig,
  ConfigurationError
} from '90dc-core';

Errors

import {
  AppError,
  ValidationError,
  AuthenticationError,
  ForbiddenError,
  NotFoundError,
  ConflictError,
  UnprocessableEntityError,
  RateLimitError,
  InternalServerError,
  ServiceUnavailableError,
  DatabaseError,
  ExternalAPIError,
  isAppError,
  isOperationalError,
  toAppError
} from '90dc-core';

Middleware

import {
  createErrorMiddleware,
  validateRequest,
  asyncHandler,
  type ErrorMiddlewareConfig
} from '90dc-core';

Database Models

import {
  PersistedUser,
  Program,
  Workout,
  Exercise,
  Badge,
  // ... many more
} from '90dc-core';

Utilities

import {
  AuthenticationUtil,
  NotificationsUtil,
  NotificationClient
} from '90dc-core';

Migration Steps

  1. Install dependencies:

    npm install 90dc-core@latest zod
    
  2. Add config validation:

    import { BaseConfigSchema, ConfigValidator } from '90dc-core';
    const config = new ConfigValidator(BaseConfigSchema);
    
  3. Add error middleware:

    import { createErrorMiddleware } from '90dc-core';
    app.use(createErrorMiddleware());
    
  4. Replace error handling:

    // Before
    if (!user) {
      ctx.status = 404;
      ctx.body = { message: 'Not found' };
      return;
    }
    
    // After
    import { NotFoundError } from '90dc-core';
    if (!user) {
      throw new NotFoundError('User');
    }
    
  5. Add request validation:

    import { validateRequest } from '90dc-core';
    router.post('/users',
      validateRequest({ body: CreateUserSchema }),
      handler
    );
    

See USAGE_EXAMPLES.md for detailed migration guide.


Building & Publishing

# Install dependencies
npm install

# Build
npm run build

# Publish to npm
npm run publish:build

Changelog

See CHANGELOG.md for version history.


License

ISC


Contributing

This is part of the 90 Day Challenge microservices architecture. See the main refactor plan for contribution guidelines.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 45

Native requirements
42 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
apn
Environment
{
  "local_name": "apn",
  "alias": false,
  "peer_metadata": null
}
^2.2.0runtime
zod
Environment
{
  "local_name": "zod",
  "alias": false,
  "peer_metadata": null
}
^4.1.12runtime
uuid
Environment
{
  "local_name": "uuid",
  "alias": false,
  "peer_metadata": null
}
^11.0.3runtime
axios
Environment
{
  "local_name": "axios",
  "alias": false,
  "peer_metadata": null
}
1.13.2runtime
debug
Environment
{
  "local_name": "debug",
  "alias": false,
  "peer_metadata": null
}
^4.4.3runtime
dotenv
Environment
{
  "local_name": "dotenv",
  "alias": false,
  "peer_metadata": null
}
^17.2.3runtime
eslint
Environment
{
  "local_name": "eslint",
  "alias": false,
  "peer_metadata": null
}
^9.39.1runtime
ioredis
Environment
{
  "local_name": "ioredis",
  "alias": false,
  "peer_metadata": null
}
^5.8.2runtime
winston
Environment
{
  "local_name": "winston",
  "alias": false,
  "peer_metadata": null
}
^3.18.3runtime
bcryptjs
Environment
{
  "local_name": "bcryptjs",
  "alias": false,
  "peer_metadata": null
}
^3.0.3runtime
jwks-rsa
Environment
{
  "local_name": "jwks-rsa",
  "alias": false,
  "peer_metadata": null
}
^3.2.0runtime
googleapis
Environment
{
  "local_name": "googleapis",
  "alias": false,
  "peer_metadata": null
}
^165.0.0runtime
@koa/router
Environment
{
  "local_name": "@koa/router",
  "alias": false,
  "peer_metadata": null
}
^15.3.0runtime
@sentry/node
Environment
{
  "local_name": "@sentry/node",
  "alias": false,
  "peer_metadata": null
}
^7.120.4runtime
jsonwebtoken
Environment
{
  "local_name": "jsonwebtoken",
  "alias": false,
  "peer_metadata": null
}
^9.0.2runtime
firebase-admin
Environment
{
  "local_name": "firebase-admin",
  "alias": false,
  "peer_metadata": null
}
^13.6.1runtime
google-auth-library
Environment
{
  "local_name": "google-auth-library",
  "alias": false,
  "peer_metadata": null
}
^10.5.0runtime
@sentry/integrations
Environment
{
  "local_name": "@sentry/integrations",
  "alias": false,
  "peer_metadata": null
}
^7.114.0runtime
@google-cloud/storage
Environment
{
  "local_name": "@google-cloud/storage",
  "alias": false,
  "peer_metadata": null
}
^7.19.0runtime
@typescript-eslint/parser
Environment
{
  "local_name": "@typescript-eslint/parser",
  "alias": false,
  "peer_metadata": null
}
^8.46.3runtime
@google-cloud/secret-manager
Environment
{
  "local_name": "@google-cloud/secret-manager",
  "alias": false,
  "peer_metadata": null
}
^6.1.1runtime
pg
Environment
{
  "local_name": "pg",
  "alias": false,
  "peer_metadata": null
}
^8.16.3development
koa
Environment
{
  "local_name": "koa",
  "alias": false,
  "peer_metadata": null
}
^2.15.3development
jest
Environment
{
  "local_name": "jest",
  "alias": false,
  "peer_metadata": null
}
^30.2.0development
nodemon
Environment
{
  "local_name": "nodemon",
  "alias": false,
  "peer_metadata": null
}
^3.1.9development
ts-jest
Environment
{
  "local_name": "ts-jest",
  "alias": false,
  "peer_metadata": null
}
^29.4.6development
@swc/cli
Environment
{
  "local_name": "@swc/cli",
  "alias": false,
  "peer_metadata": null
}
^0.7.9development
prettier
Environment
{
  "local_name": "prettier",
  "alias": false,
  "peer_metadata": null
}
^3.6.2development
@swc/core
Environment
{
  "local_name": "@swc/core",
  "alias": false,
  "peer_metadata": null
}
^1.15.0development
sequelize
Environment
{
  "local_name": "sequelize",
  "alias": false,
  "peer_metadata": null
}
^6.37.7development
@types/koa
Environment
{
  "local_name": "@types/koa",
  "alias": false,
  "peer_metadata": null
}
^2.15.0development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^5.9.3development
@types/jest
Environment
{
  "local_name": "@types/jest",
  "alias": false,
  "peer_metadata": null
}
^30.0.0development
@types/node
Environment
{
  "local_name": "@types/node",
  "alias": false,
  "peer_metadata": null
}
^24.10.0development
ts-node-dev
Environment
{
  "local_name": "ts-node-dev",
  "alias": false,
  "peer_metadata": null
}
^2.0.0development
@types/debug
Environment
{
  "local_name": "@types/debug",
  "alias": false,
  "peer_metadata": null
}
^4.1.12development
@jest/globals
Environment
{
  "local_name": "@jest/globals",
  "alias": false,
  "peer_metadata": null
}
^30.2.0development
sequelize-cli
Environment
{
  "local_name": "sequelize-cli",
  "alias": false,
  "peer_metadata": null
}
^6.6.2development
@types/validator
Environment
{
  "local_name": "@types/validator",
  "alias": false,
  "peer_metadata": null
}
^13.15.4development
@types/koa__router
Environment
{
  "local_name": "@types/koa__router",
  "alias": false,
  "peer_metadata": null
}
^12.0.5development
@types/jsonwebtoken
Environment
{
  "local_name": "@types/jsonwebtoken",
  "alias": false,
  "peer_metadata": null
}
^9.0.10development
sequelize-typescript
Environment
{
  "local_name": "sequelize-typescript",
  "alias": false,
  "peer_metadata": null
}
2.1.6development
pg
Environment
{
  "local_name": "pg",
  "alias": false,
  "peer_metadata": null
}
^8.16.3peer
sequelize
Environment
{
  "local_name": "sequelize",
  "alias": false,
  "peer_metadata": null
}
^6.37.7peer
sequelize-typescript
Environment
{
  "local_name": "sequelize-typescript",
  "alias": false,
  "peer_metadata": null
}
2.1.6peer

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "76b02cedc87a964d9163f5abc1b71ca6f52afea7",
  "tarball": "https://registry.npmjs.org/90dc-core/-/90dc-core-1.19.2.tgz",
  "fileCount": 495,
  "integrity": "sha512-jlqqNj+yvl2nQB9UCAh+ytm35SE3xZdcw9n0aK5mN3/4wlrpKfx/kPSMH/4AwNC76wcMeophfm9BhP53fQeEtQ==",
  "signatures": [
    {
      "sig": "MEQCIEEHKv5OYjpmvBygDsWU6/bh5biaMiyD6i+qHnJyQBACAiBzClQf6WCs9FCrIu18t6AItzGSRtcrQ7NIRBEkb0y2Sg==",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 1234388
}

Repository

PENDING
romapchel/90dc-core

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:30 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:905ffec1c2fdbc413ff64a1ad9ff2ffe396749e1c162008d207dcf487a28b372

Other collected versions

1.19.1012 Apr1.19.931 Mar1.19.831 Mar1.19.731 Mar1.19.631 Mar1.19.531 MarView all collected versions →