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

@trapi/core

v2.0.0

Published

Framework-neutral domain types, decorator/preset machinery and utilities shared across @trapi packages.

Readme

@trapi/core 🌱

main codecov Known Vulnerabilities npm version

Framework-neutral contract surface for TRAPI: the normalised IR (Type, Controller, Method, Parameter, …), the decorator/preset machinery (handlers, drafts, registry, loadRegistry, validatePreset), and the helpers preset authors use to author handlers (controller(...), method(...), into, append, flag, readString, …).

@trapi/core has no typescript dependency. Install it on its own to author a custom preset without pulling in the @trapi/metadata extraction pipeline (and its ~60 MB typescript peer).

Inspect the CHANGELOG.md in the repository for breaking changes.

Public API

The stable public surface is documented in the API Reference. Anything not listed there should be treated as internal even if it is re-exported, and may change without a major version bump.

Table of Contents

Installation

npm install --save @trapi/core

You typically install @trapi/core for one of three reasons:

  1. Authoring a preset — peer-depend on @trapi/core; consumers bring their own @trapi/metadata.
  2. Catching CoreError in preset-loading code paths.
  3. Reading IR types (e.g. Type, Controller) from a serialised metadata.json in a non-Node tool that doesn't want to pull typescript.

If you only consume metadata or generate OpenAPI specs, install @trapi/metadata and/or @trapi/swagger directly — they declare @trapi/core as a transitive dependency.

What's inside

| Group | Symbols | |---|---| | IR vocabulary | Type union (StringType, ObjectType, RefAliasType, …), Controller, Method, Parameter, Validator, Extension, Example, Response, Security, all is*Type guards | | Constants | TypeName, ParameterSource, CollectionFormat, MethodName, ValidatorName, MarkerName, ParamKind, DecoratorTargetKind | | Decorator/preset contract | Preset, Registry, ControllerHandler, MethodHandler, ParameterHandler, JsDoc handler variants, HandlerContext, JsDocHandlerContext, DecoratorSource, JsDocSource, ResolverMarker, UnmatchedDecoratorReport | | Authoring helpers | controller(...), method(...), parameter(...), controllerJsDoc(...), methodJsDoc(...), parameterJsDoc(...), into, append, flag, readString, readNumber, readBoolean, readStringOrStringArray, setControllerPaths, setMethodPath | | Loader / validator | loadRegistry, loadRegistryByName, resolvePresetByName, validatePreset, createRegistry, mergeRegistries, presetSchema (and per-kind handler schemas) | | Marker lookups | namesForMarker, tagsForMarker, isHiddenMarker, isExtensionMarker, isDeprecatedMarker, numericMarkerKind | | Errors | CoreError, CoreErrorCode, isCoreError | | Test helpers | literalArg, identifierArg, arrayArg, objectArg, typeArg, unresolvableArg, createHandlerContext |

Authoring a preset

import {
    type Preset,
    controller,
    method,
    parameter,
    append,
    flag,
    into,
    readString,
} from '@trapi/core';

const preset: Preset = {
    name: 'my-framework',
    controllers: [
        controller({
            match: { name: 'Controller', on: 'class' },
            apply: setControllerPaths,
        }),
    ],
    methods: [
        method({
            match: { name: 'Get', on: 'method' },
            apply: (ctx, draft) => {
                draft.verb = 'get';
                setMethodPath(ctx, draft);
            },
        }),
    ],
    parameters: [
        parameter({
            match: { name: 'Body', on: 'parameter' },
            apply: into('source').literal('body'),
        }),
        parameter({
            match: { name: 'Query', on: 'parameter' },
            apply: into('source').literal('query'),
        }),
    ],
    methodJsDoc: [
        methodJsDoc({
            match: { tag: 'hidden' },
            marker: 'hidden',
            apply: flag('hidden'),
        }),
    ],
};

export default preset;

A preset bundles handlers per kind (controllers, methods, parameters, controllerJsDoc, methodJsDoc, parameterJsDoc), and may declare extends: string[] to inherit handlers from another preset. The replaces field on a handler shadows matching parent handlers (true shadows all matches by name; '<presetName>' shadows that preset's contributions only).

See Authoring custom presets in the docs for the full handler API, marker semantics, and replaces rules.

Loading a preset

@trapi/metadata calls into loadRegistry automatically when given MetadataGenerateOptions.preset. If you want to drive it yourself:

import { loadRegistry, resolvePresetByName } from '@trapi/core';

const preset = await resolvePresetByName('@trapi/preset-decorators-express');
const registry = await loadRegistry(preset, { resolver: resolvePresetByName });

resolvePresetByName accepts an npm package name, a relative path, or a module: specifier. loadRegistry walks the extends chain via the supplied resolver and returns a flat per-kind handler list ready for the orchestrator.

Errors

The loader and validator throw CoreError with one of:

| Code | When | |---|---| | CORE_PRESET_NOT_FOUND | Every lookup path for the preset failed with ERR_MODULE_NOT_FOUND / ENOENT. | | CORE_PRESET_INVALID | The preset module loaded but evaluation failed (syntax error, throw at import time), or the preset object failed schema validation. | | CORE_PRESET_CYCLE | The extends graph contains a cycle. | | CORE_PRESET_REPLACES_NO_MATCH | A handler's replaces did not match any parent handler (only thrown in strict: true mode). |

CoreError extends BaseError from @ebec/core. It does not extend MetadataError — those are sibling roots. If you want to catch both with one handler, catch BaseError.

Structure

src/
├── controller/    # Controller + IControllerGenerator port
├── method/        # Method, MethodType, MethodName
├── parameter/     # Parameter, IParameterGenerator, ParameterSource, CollectionFormat
├── generator/     # Example, Response, Security
├── validator/     # Validator, ValidatorMeta, Validators, ValidatorName
├── resolver/      # Type union, BaseType, TypeName, Extension, type guards
├── decorator/     # Preset machinery (handlers, drafts, helpers, loader, validator)
├── error/         # CoreError, CoreErrorCode
├── variable.ts    # VariableType
└── index.ts       # Public entry point

License

Made with 💚

Published under MIT License.