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

@ir-kit/fn-schema-core

v0.2.0

Published

Language-agnostic core for fn-schema: extract function input/output JSON Schemas from source code. Defines the Extractor contract and ships emitters (files, bundle, OpenAPI) that operate on the shared FunctionInfo IR.

Readme

@ir-kit/fn-schema-core

Language-agnostic IR + emitters for fn-schema. Defines the Extractor contract that language-specific packages implement, and ships the orchestration + output paths every extractor shares.

When to use this directly

Most users don't import core — they use the cli or @ir-kit/fn-schema-typescript (which re-exports a pre-wired extract). Reach for core when you want to:

  • register multiple extractors in the same run (e.g. TS + Python, when Python lands)
  • keep a long-lived Project warm across many extract() calls
  • build your own emitter on top of the orchestrator

Quick start

import { createProject } from "@ir-kit/fn-schema-core"
import { typescript } from "@ir-kit/fn-schema-typescript"

const project = createProject({
  cwd: process.cwd(),
  tsConfigPath: "./tsconfig.json",
  extractors: [typescript()],
})

const result = await project.extract({
  files: ["src/api/handlers.ts"],
  schema: { identity: "x-fn-schema-ts", transport: "x-fn-schema-transport" },
})

project.dispose()

Discovery without schemas

Project.discover() walks the same files but stops at function detection — no schema generation. Use it when you only need names, locations, JSDoc tags, and the like.

const { signatures, stats } = await project.discover({
  files: ["src/**/*.ts"],
  include: { jsDocTag: "schema" },
})
for (const fn of signatures) console.log(fn.name, fn.file, fn.location)

Emitters

import { emit } from "@ir-kit/fn-schema-core"

emit.toFiles(result, { dir: "generated", format: "json-pretty" })
emit.toBundle(result, { pretty: true })
emit.toBundleTypesModule(result, { jsonImport: "./schemas.json" })
emit.toOpenAPI(result, { title: "my-api" })
  • toFiles — one JSON per signature
  • toBundle — single JSON with all signatures + shared definitions
  • toBundleTypesModule — TS wrapper exporting the bundle under literal-typed signature ids and definition names (pair with loader)
  • toOpenAPI — components-only OpenAPI 3.1 doc; tuples use prefixItems

Schema knobs

schema: {
  dialect: "draft-07" | "draft-2020-12" | "openapi-3.1",
  expose: "all" | "export" | "none",
  topRef: false,
  additionalProperties: false,

  // user overrides built-in mappings (Date, File, Buffer, …)
  typeMappers: { MyType: { type: "string", format: "uuid" } },

  // off-by-default vendor extensions
  identity: "x-fn-schema-ts",            // attach originating TS type name
  transport: "x-fn-schema-transport",    // attach multipart/base64 hint
  sourceLocations: "x-fn-schema-source", // attach file:line:col
}

Diagnostics

Every mapping decision is observable:

| Code | Severity | When | |---|---|---| | TYPE_MAPPED | info | Well-known TS type rewritten to canonical JSON Schema | | LOSSY_MAPPING | warning | Mapping lost information (e.g. bigintinteger) | | NOT_REPRESENTABLE | error | Type can't be represented in JSON Schema (e.g. symbol) | | GENERIC_SKIPPED | warning | Generic function skipped (set signature.generics: "erase" to override) | | DUPLICATE_ID | warning | Definition emitted with conflicting shapes from two functions | | EXTRACTOR_FAILURE | error | Extractor threw on a function | | EMPTY_RESULT | info | No signatures matched the filter | | NO_EXTRACTOR | warning | A file's extension isn't claimed by any registered extractor |

Subscribe via extract({ onDiagnostic: (d) => ... }) or read result.diagnostics after.

Extractor contract

Other languages plug in by implementing:

interface Extractor {
  readonly extensions: readonly string[]
  readonly language: string
  init(opts: ExtractorInitOptions): Promise<ExtractorInstance>
}

interface ExtractorInstance {
  discover(files: readonly string[], filter: ResolvedFilter): Promise<FunctionInfo[]>
  toSchemas(fn: FunctionInfo, opts: ResolvedSignatureOptions & ResolvedSchemaOptions): Promise<SignaturePair>
  refresh(files: readonly string[]): void
  dispose(): void
}