npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@absmartly/api-mocks

v1.0.8

Published

OpenAPI-driven mock server, typed factories, and schema validation for the ABsmartly API. Built on [MSW (Mock Service Worker)](https://mswjs.io/) with handlers auto-generated from the ABsmartly OpenAPI specification.

Readme

@absmartly/api-mocks

OpenAPI-driven mock server, typed factories, and schema validation for the ABsmartly API. Built on MSW (Mock Service Worker) with handlers auto-generated from the ABsmartly OpenAPI specification.

Installation

npm install --save-dev @absmartly/api-mocks

Peer dependency: This package requires msw v2+:

npm install --save-dev msw

Quick Start

import { createServer } from '@absmartly/api-mocks/server';
import { beforeAll, afterEach, afterAll, test, expect } from 'vitest';

const server = createServer('https://your-instance.absmartly.com/v1');

beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('fetches experiments', async () => {
  const response = await fetch('https://your-instance.absmartly.com/v1/experiments');
  const data = await response.json();
  expect(response.ok).toBe(true);
});

Package Exports

| Import path | Description | |---|---| | @absmartly/api-mocks | Everything: factories, handlers, validation, and createServer | | @absmartly/api-mocks/server | createServer(baseUrl) -- creates a pre-configured MSW server | | @absmartly/api-mocks/handlers | MSW request handlers (generated + error simulation) | | @absmartly/api-mocks/factories | Faker-based factory functions for all API resources | | @absmartly/api-mocks/validation | Schema validation utilities powered by AJV |

MSW Mock Server

createServer(baseUrl) returns an MSW setupServer instance with all generated handlers pre-registered.

import { createServer } from '@absmartly/api-mocks/server';

const server = createServer('https://your-instance.absmartly.com/v1');

Vitest Setup

Create a setup file to start/stop the server around your tests:

// test/setup.ts
import { beforeAll, afterEach, afterAll } from 'vitest';
import { createServer } from '@absmartly/api-mocks/server';

const server = createServer('https://your-instance.absmartly.com/v1');

beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Then reference it in your Vitest config:

// vitest.config.ts
export default defineConfig({
  test: {
    setupFiles: ['./test/setup.ts'],
  },
});

Pre-configured Server

The package also exports a pre-configured server instance that reads the base URL from environment variables:

import { server } from '@absmartly/api-mocks/src/mocks/server';

The base URL is resolved in this order:

  1. API_BASE_URL environment variable
  2. ABSMARTLY_API_ENDPOINT environment variable
  3. https://sandbox.absmartly.com/v1 (placeholder default — only used by MSW mocks, which intercept all requests before they reach the network)

Handlers

Generated Handlers

Handlers are auto-generated from the OpenAPI specification. Every endpoint in the spec gets a corresponding MSW handler that returns realistic example data.

import { createHandlers } from '@absmartly/api-mocks/handlers';

const handlers = createHandlers('https://your-instance.absmartly.com/v1');

The generated handlers cover 40+ API resources including experiments, goals, metrics, segments, users, teams, applications, environments, and more.

How generated handlers work:

  • GET (list) -- Returns the static example from the OpenAPI spec
  • GET (by ID) -- Clones the example and sets the id field from the URL path parameter
  • POST / PUT / PATCH -- Clones the example, deep-merges the request body into the response, and validates the request using withValidation()
  • DELETE -- Returns 204 No Content

The deep-merge strategy preserves response arrays (arrays from the example response take precedence over arrays in the request body), which ensures list fields always return realistic data.

Error Simulation Handlers

In addition to the generated handlers, the package provides error simulation handlers for testing error scenarios:

import { createErrorHandlers } from '@absmartly/api-mocks/handlers';

const errorHandlers = createErrorHandlers('https://your-instance.absmartly.com/v1');

These handlers simulate common error cases:

| Endpoint | Trigger | Response | |---|---|---| | POST /experiments | Missing name | 400 -- name is required | | POST /experiments | name: "duplicate_name" | 409 -- already exists | | POST /experiments | Missing unit_type_id | 400 -- unit_type_id is required | | PUT /experiments/999/start | ID = 999 | 400 -- already running | | PUT /experiments/888/stop | ID = 888 | 400 -- not running | | POST /goals | Missing name | 400 -- name is required | | POST /goals | name: "duplicate" | 409 -- already exists | | POST /segments | Missing name or value_source_attribute | 400 -- field is required | | DELETE /segments/666 | ID = 666 | 409 -- in use by active experiments | | POST /api_keys | Missing name | 400 -- name is required |

Factories

All factories follow the same pattern: createMock*(overrides?) returns a single instance, createMock*s(count) returns an array. Every factory is typed using the generated TypeScript types from the OpenAPI schema.

import { createMockExperiment, createMockExperiments } from '@absmartly/api-mocks/factories';

// Single instance with defaults
const experiment = createMockExperiment();

// With overrides
const experiment = createMockExperiment({
  name: 'my_test',
  state: 'running',
});

// Multiple instances
const experiments = createMockExperiments(5);

Available Factories

| Factory | Type | |---|---| | createMockExperiment / createMockExperiments | ExperimentShort | | createMockGoal / createMockGoals | Goal | | createMockSegment / createMockSegments | Segment | | createMockMetric / createMockMetrics | Metric | | createMockUser / createMockUsers | User | | createMockTeam / createMockTeams | Team | | createMockApplication / createMockApplications | Application | | createMockEnvironment / createMockEnvironments | Environment | | createMockUnitType / createMockUnitTypes | UnitType | | createMockApiKey / createMockApiKeys | ApiKey | | createMockWebhook / createMockWebhooks | Webhook | | createMockRole / createMockRoles | Role | | createMockPermission / createMockPermissions | Permission | | createMockPermissionCategory / createMockPermissionCategories | PermissionCategory | | createMockMetricCategory / createMockMetricCategories | MetricCategory | | createMockAlert / createMockAlerts | Alert | | createMockNote / createMockNotes | Note | | createMockExperimentTag / createMockExperimentTags | ExperimentTag | | createMockGoalTag / createMockGoalTags | GoalTag | | createMockMetricTag / createMockMetricTags | MetricTag |

Validation

The validation layer uses AJV to validate request and response payloads against the OpenAPI schema. All validation functions load and dereference the bundled OpenAPI spec automatically.

Request Validation (Lenient)

validateRequest is intentionally lenient -- it strips required, minItems, minProperties, and pattern constraints so you can send partial payloads in tests. It validates structure and types only.

import { validateRequest } from '@absmartly/api-mocks/validation';

const result = await validateRequest('/goals', 'POST', {
  name: 'My Goal',
});
// result: { valid: true, errors: [] }

Response Validation (Strict)

validateResponse applies the full schema including all constraints.

import { validateResponse } from '@absmartly/api-mocks/validation';

const result = await validateResponse('/goals', 'GET', 200, responseData);
if (!result.valid) {
  console.log(result.errors);
  // [{ path: '/items/0', message: '...', keyword: 'type' }]
}

Strict Request/Response Validation

For when you want full constraint checking on requests too:

import { validateRequestStrict, validateResponseStrict } from '@absmartly/api-mocks/validation';

const result = await validateRequestStrict('/goals', 'POST', payload);

findUnknownProperties can detect extra properties not defined in the schema:

import { findUnknownProperties, loadOpenAPISpec } from '@absmartly/api-mocks/validation';

const spec = await loadOpenAPISpec();
const unknowns = findUnknownProperties(data, schema, spec);

Handler Validation Wrapper

withValidation wraps an MSW handler resolver to automatically validate incoming requests (and optionally responses):

import { withValidation } from '@absmartly/api-mocks/validation';
import { http, HttpResponse } from 'msw';

http.post(
  `${baseUrl}/goals`,
  withValidation('/goals', 'POST', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({ ok: true, goal: body }, { status: 201 });
  }, {
    validateRequests: true,   // default: true
    validateResponses: false, // default: false
  })
);

When request validation fails, it returns a 422 response:

{
  "ok": false,
  "error": "validation_error",
  "message": "Request validation failed",
  "status": 422,
  "details": [{ "path": "/name", "message": "must be string", "keyword": "type" }]
}

Payload Generation

generatePayloadForEndpoint creates a minimal valid payload that satisfies the request schema for a given endpoint:

import { generatePayloadForEndpoint } from '@absmartly/api-mocks/validation';

const payload = await generatePayloadForEndpoint('/goals', 'POST', {
  name: 'My Custom Goal',
});

It generates sensible defaults for each type (string -> "test-string", integer -> 1, date-time -> "2025-01-01T00:00:00.000Z", email -> "[email protected]", etc.) and deep-merges any overrides you provide.

Schema Inspection

Lower-level functions for working with the OpenAPI spec directly:

import {
  loadOpenAPISpec,
  getSchemaForEndpoint,
  getRequestSchemaForEndpoint,
  createValidator,
  validateAgainstSchema,
} from '@absmartly/api-mocks/validation';

// Load the full dereferenced spec
const spec = await loadOpenAPISpec();

// Get the response schema for a specific endpoint
const responseSchema = await getSchemaForEndpoint('/experiments', 'GET', 200);

// Get the request body schema
const requestSchema = await getRequestSchemaForEndpoint('/goals', 'POST');

// Compile a reusable validator
const validate = createValidator(responseSchema);
const isValid = validate(data);

// One-shot validation
const result = await validateAgainstSchema(data, schema, { coerceTypes: true });

OpenAPI Specification

The package bundles the ABsmartly API OpenAPI 3.0 specification:

openapi/
  openapi.yaml              # Main spec (references paths/ and components/)
  openapi.bundle.yaml       # Fully dereferenced bundle (used at runtime)
  openapi_with_examples.yaml
  paths/                    # Per-resource path definitions (44 files)
  examples/                 # Response examples per resource
  components/               # Shared schema components
  live-payloads/            # Sanitized payloads captured from the live API

The bundled spec at openapi/openapi.bundle.yaml is what the validation layer loads at runtime. It has all $ref references resolved inline.

Code Generation

Two things are auto-generated from the OpenAPI spec and must be regenerated whenever the spec changes:

TypeScript Types

npm run generate:types

Runs openapi-typescript to produce src/generated/schema.d.ts from openapi/openapi.yaml. This file contains TypeScript interfaces for all API paths, operations, and component schemas. All factories are typed using these generated types.

MSW Handlers

npm run generate:handlers

Runs scripts/generate-handlers.mjs to produce one handler file per API resource in src/handlers/generated/. The generator:

  1. Reads each path from the OpenAPI spec
  2. Extracts response examples (preferring _200/_201 suffixed examples)
  3. Creates MSW handlers for each HTTP method (GET, POST, PUT, DELETE, etc.)
  4. Wraps POST/PUT/PATCH handlers with withValidation() for request validation
  5. Generates an index.ts that aggregates all resource handlers

Regenerate Everything

npm run generate

This runs both generate:types and generate:handlers. It also runs automatically before npm test (via pretest) and before npm publish (via prepublishOnly).

Testing

Unit Tests

npm test              # Watch mode
npm run test:run      # Single run
npm run test:coverage # With coverage report

Unit tests validate the mock server handlers, factories, and validation logic using MSW's in-memory server. No network access required.

Contract Tests

npm run test:contract

Validates that the mock server responses conform to the OpenAPI schema. Compiles schemas with AJV and checks that generated responses pass validation.

Live API Validation

npm run validate:live

Runs 40+ test files against the real ABsmartly API, validating that actual API responses match the OpenAPI schema. Requires API_KEY and API_BASE_URL environment variables (or a .env.local file).

npm run validate:live:report   # Generates a markdown report
npm run validate:comprehensive # Full validation suite with reports

Mutation Tests

npm run validate:mutations       # Interactive (asks for confirmation)
npm run validate:mutations:force # Non-interactive

Full CRUD lifecycle tests that create, read, update, and delete resources on the live API. Includes automatic cleanup of created resources via a ResourceTracker.

Schemathesis

npm run validate:schemathesis

Property-based API testing using Schemathesis. Generates random valid requests from the OpenAPI spec and checks all responses for conformance. Requires Python 3.11+ and the schemathesis pip package.

Environment Variables

| Variable | Description | Default | |---|---|---| | API_BASE_URL | Base URL for the ABsmartly API (required for live tests and scripts) | -- | | ABSMARTLY_API_ENDPOINT | Alternative base URL variable | -- | | API_KEY | API key for live API tests | -- | | ABSMARTLY_API_KEY | Alternative API key variable | -- | | ENABLE_LIVE_API_TESTS | Set to true to enable live API test suites | false |

Create a .env.local file for local development:

API_KEY=your_api_key_here
API_BASE_URL=https://your-instance.absmartly.com/v1

CI/CD

Pushes to main automatically run tests and publish a new patch version to npm via GitHub Actions with npm trusted publishing (OIDC -- no tokens required).

Project Structure

src/
  index.ts                  # Main export aggregator
  server.ts                 # createServer(baseUrl) factory
  mocks/
    server.ts               # Pre-configured MSW server instance
    handlers.ts             # Handler initialization from env vars
  handlers/
    index.ts                # Handler exports and composition
    errors.ts               # Error simulation handlers
    generated/              # Auto-generated (one file per resource)
  factories/                # Faker-based data factories (18 resources)
  validation/
    schema-validator.ts     # OpenAPI spec loading and AJV validation
    request-validator.ts    # Lenient request validation
    response-validator.ts   # Strict response validation
    validated-handler.ts    # MSW handler validation wrapper
    strict-validator.ts     # Strict validation + unknown property detection
    payload-generator.ts    # Generate valid payloads from schemas
  generated/
    schema.d.ts             # Auto-generated TypeScript types
  __tests__/                # Unit tests
  contract-tests/           # Schema contract tests
  live-validation/          # Live API validation tests
  live-validation-mutations/# CRUD lifecycle mutation tests
openapi/
  openapi.yaml              # Main OpenAPI spec
  openapi.bundle.yaml       # Dereferenced bundle
  paths/                    # Per-resource path definitions
  examples/                 # Response examples
  components/               # Shared schemas
  live-payloads/            # Captured live API payloads
scripts/
  generate-handlers.mjs     # Handler generation from OpenAPI
  generate-live-validation-tests-v2.mjs
  validate-live-api.sh
  run-mutation-tests.sh
  sync-examples-from-live.mjs

License

Proprietary - ABsmartly