Adaptate is a TypeScript library for dynamic and adaptable model validation using Zod, interoperable with OpenAPI. A pnpm monorepo (Turborepo-orchestrated) with two publishable packages.
packages/core/: Schema transformation engine (transformSchema,makeConditionalSchemaTransformer)packages/utils/: Feature-complete OpenAPI ↔ Zod conversion utilities + YAML loading with full$refresolution
Requires Docker or Podman and Dev Containers (VS Code: Microsoft ms-vscode-remote.remote-containers; Cursor: Anysphere anysphere.remote-containers — search Extensions for “Dev Containers”). Open the repo with Dev Containers: Reopen in Container. The workspace is the bind-mounted repository only (your host home is not mounted by default—keep it that way unless you deliberately need extra mounts).
Configuration lives in .devcontainer/devcontainer.json: Node 24 image, pnpm@11.1.1 via Corepack (matches root engines and packageManager). After the container starts, postCreateCommand runs pnpm install --frozen-lockfile --ignore-scripts, aligned with CI. Short how-to: .devcontainer/README.md.
- Install:
pnpm installonly — do not usenpm installat the repo root (supply-chain posture in.npmrc+pnpm-workspace.yamlis for pnpm; npm bypasses or mismatches key defenses; seepackage.jsonpackageManager) - Build:
pnpm build(runs Turborepo pipeline: check-types → test → build) - Test:
npx vitest run --coverage(single run) orpnpm test(watch mode) - Typecheck:
npx turbo run check-types - Lint:
pnpm lint— Oxlint (correctness / general fast lint, see.oxlintrc.json) then ESLint deprecation-only (@typescript-eslint/no-deprecated, seeeslint.config.js). Per-package:pnpm turbo run lint. - Lint fixes (Oxlint auto-fix where supported):
pnpm run lint:fixthen address any remaining ESLint deprecation findings by hand or codemod. - Coverage badge:
pnpm run coveragebadge
- TypeScript: Strict typing, no
any, ESM modules throughout - Variable declarations: Use
letby default (user preference).constis allowed only when reassignment is impossible. - Naming: CamelCase for types/interfaces, camelCase for functions/variables
- Imports: Group by type (external libs, internal workspace refs)
- Zod patterns: Use
unwrap()notrequired()for unwrapping optional schemas
- Framework: Vitest with v8 coverage
- Location: Tests live in
src/__tests__/*.test.tsnext to implementation - Assertions: Use
toThrowErrorMatchingInlineSnapshotandtoMatchInlineSnapshotfor Zod errors - Coverage: All packages measured;
packages/utils/src/index.ts(re-export only) excluded - Cross-package: Core tests import utils via
#utils/openapialias
- Atomic changes per logical unit
- Messages: "feat: add feature", "fix: resolve issue", "refactor: improve code"
- No secrets or binaries
- Default branch:
main - Feature branches:
cursor/<short-description>-<suffix>for cloud agents (e.g.cursor/zod-v4-migration-3f1e)
Operational guides for common tasks live in skills/. Any coding agent should check this directory when performing the relevant task:
| Skill | When to use |
|---|---|
skills/add-feature.md |
Implementing a new capability |
skills/fix-bug.md |
Investigating and fixing a reported issue |
skills/verify.md |
Running quality gates before committing |
skills/add-test.md |
Writing new tests |
skills/refactor.md |
Restructuring code without changing behavior |
skills/release.md |
Preparing a version bump for publishing |
- Run
npx turbo run check-typesafter TypeScript changes - Run
pnpm lintto run Oxlint and ESLint (deprecation) on package sources (also enforced in GitHub Actions:.github/workflows/ci.ymlruns lint, thenpnpm test, thenturbo run build) - Run
npx vitest run --coverageto verify tests pass - Build pipeline order:
check-types→test→build(enforced byturbo.json) - No force pushes to
main - Use tools efficiently, cache results
- Escalate on failures
- Before committing: follow
skills/verify.md
This is a TypeScript library monorepo (pnpm workspaces + Turborepo) with two packages:
@adaptate/core— Schema transformation engine (Zod-based)@adaptate/utils— Feature-complete OpenAPI ↔ Zod conversion utilities
| Action | Command |
|---|---|
| Install deps | pnpm install |
| Type check | npx turbo run check-types |
| Test (single run) | npx vitest run --coverage |
| Test (watch) | pnpm test |
| Lint | pnpm lint |
| Build | pnpm build |
- Package manager: Use pnpm only (
pnpm install).npm installat the repo root breaks from the repo’s supply-chain defenses (.npmrc,pnpm-workspace.yaml) and can diverge from CI — not supported for developing Adaptate.
| Tool | Role |
|---|---|
Oxlint (.oxlintrc.json) |
Fast lint; default correctness category for CI. Expand categories locally if desired (many style rules warn loudly on tests). |
ESLint (eslint.config.js) |
Deprecation detection only: @typescript-eslint/no-deprecated (requires types from dependencies). |
- TypeScript is a workspace
devDependency(typescript@6.0.3at the repo root and in@adaptate/core/@adaptate/utils) sotscis available from each package’snode_modules/.binafterpnpm install. No globaltypescriptinstall is required. - The
turbo.jsonbuild task depends on^test, which depends oncheck-types. Runningpnpm buildtriggers the full pipeline: check-types → test → build. - There is a single
tsconfig.jsonat the root used by both packages; individual packages do not have their own tsconfigs. - Tests use Vitest (not Jest), despite
@types/jestbeing present in root devDependencies. - No legacy ESLint config beyond
eslint.config.js(flat config). Deprecation-only rules; general lint is Oxlint. - The
jest.config.mjsat the root is legacy and non-functional (references missingtsconfig.jest.json); ignore it. packages/utilsbuilds both a browser bundle (build/) and an SSR bundle (ssr-build/). Node builtins are externalized in both.- Bundler: Both packages use Vite 8 (
vite@^8.0.10in each package; lockfile pinsvite@8.0.10). Productionvite builduses Rolldown (Vite’s default bundler in v8). There is norolldown-vitedependency alias and nopnpm.overridesentry for Vite—stay on plainvitefrom the registry. - After a Vite major bump, run
pnpm buildand spot-checkpackages/core/build/,packages/utils/build/, andpackages/utils/ssr-build/(entry files, chunk names,.mapfiles) before releasing. - Socket.dev package scores blend supply chain, vulnerability, quality, maintenance, and license signals; the headline badge is not a simple average (see Package Scores). On the
adaptateoverview, the Socket 69 headline aligns with Supply Chain Security 69 (low adoption and related signals hurt that dimension). Other gauges are typically Vulnerability 100, Quality 100, Maintenance 89, License 100—Socket may still show a Quality-tagged notice such as “Unpopular package” (low npm footprint) even when the Quality gauge is high. Use the live per-category bars and warnings on the version page; numbers drift by version (skills/release.mdfor post-release re-checks). - Path aliases:
#utils/*maps to../utils/src/*in core'spackage.jsonimports;@adaptate/*paths are in roottsconfig.json.