Latest Supply Chain Attack:Mini Shai-Hulud Hits @antv npm Packages, 639 Versions Compromised.Learn More
Sign In

adaptate

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

adaptate

Dynamic and Adaptable Model Validator Using Zod, Interoperable with OpenAPI

latest
Source
npmnpm
Version
2.2.2
Version published
Weekly downloads
804
491.18%
Maintainers
1
Weekly downloads
 
Created
Source

Adaptate

Dynamic and Adaptable Model Validator Using Zod, Interoperable with OpenAPI

npm: adaptate npm: @adaptate/core npm: @adaptate/utils downloads / month minzipped types: included

CI Coverage Socket.dev supply chain License: MIT Last commit Issues Stars

TypeScript Node >=24 pnpm 11.1.1 Zod peer Dev Container

Overview

adaptate is a dynamic and adaptable model validator that leverages Zod for schema validation and is interoperable with OpenAPI. Define a single optional Zod schema for your data model, then use configuration objects to declare which fields each consumer requires — at runtime.

Packages

PackageDescription
@adaptate/coreSchema transformation engine — make fields required based on config
@adaptate/utilsOpenAPI ↔ Zod conversion, YAML spec loading with $ref resolution

Installation

pnpm add @adaptate/core
# or
npm install @adaptate/core

For OpenAPI utilities:

pnpm add @adaptate/utils
# or
npm install @adaptate/utils

Peer dependency: zod@^3.23.8 || ^4.0.0

The Problem

In component-oriented applications, different components consume different subsets of the same data model. One component needs name and age, another needs address.city, and a third needs everything. The data often comes from different API endpoints with varying completeness.

Without runtime validation per consumer, you either:

  • Make everything optional (no safety)
  • Make everything required (breaks partial views)
  • Maintain separate schemas per component (duplication nightmare)

Adaptate solves this: define one schema with all fields optional, then use a config object to declare what each consumer requires.

Usage

Make Fields Required by Configuration

There are two common ways to create a fully optional schema:

1. Using .deepPartial() (recommended)

import { z } from 'zod';
import { transformSchema, type Config } from '@adaptate/core';

const schema = z.object({
  name: z.string(),
  age: z.number(),
  address: z.object({
    street: z.string(),
    city: z.string(),
  }),
}).deepPartial();

const config = {
  name: true,
  age: true,
  address: { city: true },
} satisfies Config<z.infer<typeof schema>>;

const updatedSchema = transformSchema(schema, config);

updatedSchema.parse({ name: 'Davin', age: 30, address: { city: 'Pettit' } }); // passes
updatedSchema.parse({ name: 'Davin', age: 30, address: { street: 'Main St' } }); // throws

2. Manual .optional() (still works)

import { z } from 'zod';
import { transformSchema } from '@adaptate/core';

const schema = z.object({
  name: z.string().optional(),
  age: z.number().optional(),
  address: z.object({
    street: z.string().optional(),
    city: z.string().optional(),
  }).optional(),
});

// ... same config and usage as above

Conditional Requirements

Make fields required based on runtime data
import { z } from 'zod';
import { makeConditionalSchemaTransformer } from '@adaptate/core';

const schema = z.object({
  parentContactNumber: z.number().optional(),
  age: z.number().optional(),
});

const config = {
  parentContactNumber: { requiredIf: (data: any) => data.age < 18 },
  age: true,
};

const data = { age: 17 };
const transformer = makeConditionalSchemaTransformer(data)(schema, config);

transformer.run(); // throws — parentContactNumber required because age < 18

OpenAPI ↔ Zod Conversion

Convert OpenAPI schemas to Zod and back (now fully feature-complete)

Load and dereference an OpenAPI spec:

import { getDereferencedOpenAPIDocument } from '@adaptate/utils';

const doc = await getDereferencedOpenAPIDocument({
  location: 'filesystem',
  callSiteURL: import.meta.url,
  relativePathToSpecFile: './api-spec.yml',
});

Convert OpenAPI schema to Zod:

import { openAPISchemaToZod } from '@adaptate/utils';

const zodSchema = openAPISchemaToZod({
  type: 'object',
  required: ['age'],
  properties: {
    name: { type: 'string', minLength: 2 },
    age: { type: 'integer', minimum: 0 },
  },
});

Convert Zod to OpenAPI schema:

import { z } from 'zod';
import { zodToOpenAPISchema } from '@adaptate/utils';

const openAPISchema = zodToOpenAPISchema(
  z.object({ name: z.string().min(2), age: z.number().int() })
);

See @adaptate/utils README for full documentation.

Design Philosophy

Compact & Powerful: The core transformation logic is intentionally compact — fewer than 100 lines of code. Complex nested transformations (deep objects, arrays with wildcards, conditional requirements) are handled elegantly through recursion. This keeps the API surface small while delivering sophisticated behavior with minimal cognitive overhead.

For a deeper dive, see DESIGN.md which covers:

  • Detailed code walkthroughs
  • Runtime complexity analysis (O(N) time, O(D) space)
  • Performance characteristics and trade-offs
  • Comparison with alternative approaches

Development

This is a pnpm monorepo orchestrated with Turborepo.

Package manager: Use pnpm only when working in this repository (pnpm install). This repo’s install/build safety posture is defined for pnpm (.npmrc, pnpm-workspace.yaml: lifecycle restrictions, store integrity, release-age gates, etc.). npm install at the root is unsupported — npm ignores or mishandles several of those controls and may resolve dependencies differently than CI, weakening protections against supply-chain attacks that the config is meant to mitigate. Root package.json pins packageManager. The Installation section above (pnpm add / npm install for @adaptate/*) applies to consumers installing published packages from the npm registry.

Requirements: Node.js ≥ 20, pnpm 9.12.3

pnpm install          # Install dependencies
pnpm build            # Full pipeline: check-types → test → build
pnpm test             # Run Vitest in watch mode
npx vitest run        # Single test run
npx turbo run check-types  # TypeScript type checking

Project Structure

├── .devcontainer/     # optional Dev Container (Node 24 + pnpm)
├── packages/
│   ├── core/         # @adaptate/core — schema transformation
│   └── utils/        # @adaptate/utils — OpenAPI utilities
├── skills/           # Tool-agnostic agent SOPs
├── AGENTS.md         # Agent guidelines
├── CODING_STYLE.md   # Coding conventions
└── turbo.json        # Turborepo task graph

See AGENTS.md and skills/ for development guidelines and operational procedures. Optional dev container: .devcontainer/README.md, .devcontainer/devcontainer.json.

Credits

This library recreates and generalizes a pattern originally observed at Oneflow AB, where the same data model was consumed by different components with varying required fields depending on context.

Development note: Initial prototype was created with ChatGPT Canvas. All important caveats and refinements were manually corrected by the author. The PR (#21) marks the first use of AI coding agents (Grok) in the project. Cursor Cloud Agent prepared the repo for agentic development workflows.

License

MIT

Keywords

Zod

FAQs

Package last updated on 14 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts