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

@contextual-io/typegen

v0.1.1

Published

Types for a Contextual application's contextual.yaml: a TypeScript 7.1 content mapper and generated declarations for earlier compilers.

Readme

@contextual-io/typegen

@contextual-io/typegen is an optional companion to @contextual-io/sdk. It provides TypeScript types for an application's contextual.yaml: typed Object Type handles and records, route parameters, handler signatures, and event destinations. The core SDK is filesystem-free and accepts explicit configuration. It has no typegen, YAML, or TypeScript beta dependency, and works without these files or tools.

With typegen, the application owns contextual.yaml, which selects Object Types, routes, and events. An optional contextual.lock.yaml holds the Registry definitions that give records their shape.

Typegen reads the handler manifest shown below, with app, runtime, objects, http, and events. The CLI's Application deployment manifest and @contextual-io/app's intentVersion: 1 format have their own schemas.

Choose one of two ways to get types. Runtime value imports use a separate, explicit loader:

| Path | Supported compiler or runtime | Output | | --- | --- | --- | | Generated declarations | TypeScript 5.9.3 | contextual-typegen writes contextual.d.yaml.ts | | Opt-in content mapper | TypeScript 7.1.0-beta | Virtual declarations for contextual.yaml, with diagnostics and definitions mapped into the YAML | | @contextual-io/typegen/register | Node.js 24 | The objects catalog for value imports |

These are the exact tested compiler versions, not a compatibility claim for other TypeScript versions or historical SDK releases. Both static paths emit identical declaration text. Use one at a time, following Switching modes.

Install

The Contextual packages are not published yet. The registry installation commands below apply after publication.

Use Node.js 24 for installation, codegen, the mapper, and the runtime loader. In your application's directory, choose npm, pnpm, or Yarn Classic 1 with a node_modules installation:

# npm
npm install @contextual-io/sdk @contextual-io/api-types @contextual-io/typegen
npm install --save-dev --save-exact [email protected] @types/[email protected]

# pnpm
pnpm add @contextual-io/sdk @contextual-io/api-types @contextual-io/typegen
pnpm add --save-dev --save-exact [email protected] @types/[email protected]

# Yarn Classic 1
yarn add @contextual-io/sdk @contextual-io/api-types @contextual-io/typegen
yarn add --dev --exact [email protected] @types/[email protected]

With Yarn Classic 1, use yarn run for the package scripts below. Run the source and compiled clients with the direct node --import ... commands shown; Node resolves their dependencies from node_modules.

The declarations import types from @contextual-io/sdk, so install it explicitly as shown above. Each package has its own version. The api-types version must satisfy the caret ranges in the packed package manifests; ^0.0.1 accepts only 0.0.1. Typegen depends on @contextual-io/api-types, yaml, and zod, which the package manager installs automatically.

Compatibility is checked against the SDK packed alongside typegen by the packed consumer and content mapper acceptance checks. Typegen declares no SDK dependency or peer range. Equal version numbers do not establish compatibility; SDK API changes need acceptance checks against the generated declarations and runtime loader before using a new combination.

Before registry publication, install the required package tarballs together in your application directory:

api_types_version=0.0.1 # set each version from its tarball file name
sdk_version=0.0.1
typegen_version=0.0.1
npm install "./contextual-io-api-types-$api_types_version.tgz" "./contextual-io-sdk-$sdk_version.tgz" "./contextual-io-typegen-$typegen_version.tgz"

For core SDK usage alone, omit @contextual-io/typegen and the typegen setup below. For typegen used only during development and builds, you can put it in devDependencies; keep it in runtime dependencies if you use @contextual-io/typegen/register in production.

Quick start

The following setup uses generated declarations with TypeScript 5.9.3. All paths belong to your application:

inventory/
  package.json
  tsconfig.json
  contextual.yaml
  contextual.lock.yaml       # optional
  contextual.d.yaml.ts       # generated
  src/
    items.ts
    main.ts

Create contextual.yaml at the application root:

manifestVersion: 1
app:
  id: inventory
  name: Inventory
runtime: nodejs24
objects:
  inventory-item:
    operations: [read, create]
http:
  auth: none
  routes:
    getItem:
      handler: { file: src/items.ts, export: getItem }
      method: GET
      path: /items/:id

contextual.lock.yaml, beside it, is optional. Each entry is an Object Type definition captured from Registry, keeping only id, type, objectType, name, display, defaultListStyle and schema:

lockVersion: 1
objects:
  inventory-item:
    definition:
      id: inventory-item
      type: custom
      objectType: internal
      name: Inventory Item
      display: default
      defaultListStyle: table
      schema:
        type: object
        primaryKey: id
        required: [id, title]
        properties:
          id: { type: string }
          title: { type: string }
          quantity: { type: integer, minimum: 0 }

The route's handler, src/items.ts:

import { HttpResponse } from "@contextual-io/sdk"

import type { Handlers } from "../contextual.yaml"

export const getItem: Handlers["getItem"] = async ({ params }, ctx) => {
  const { data } = await ctx.object("inventory-item").get(params.id) // params from the route path
  return HttpResponse.json(200, { title: data.title })
}

A standalone client, src/main.ts:

import { Contextual } from "@contextual-io/sdk"
import { connectionFromEnv } from "@contextual-io/sdk/env"

import { objects } from "../contextual.yaml"

const client = new Contextual({ ...connectionFromEnv(process.env), objects })
const { data: item } = await client.object("inventory-item").get("one") // the read type from the lock
console.log(item.title, item.quantity)

Here, ../contextual.yaml resolves from src/ to your own application root. It does not refer to a file shipped by the SDK. Nested sources can use another parent segment as needed, while staying within that root.

Add the generated-declaration configuration, then run npm run build, pnpm run build, or yarn run build. To run the standalone client from source with Node.js 24:

node --import @contextual-io/typegen/register src/main.ts

The client reads credentials and endpoints from environment input you supply through connectionFromEnv(process.env). The manifest supplies the Object Type catalog, not credentials. A handler such as getItem needs an application-owned host or server to invoke it; typegen does not start one.

What the declarations provide

  • objects declares each selected Object Type with its operations and primary key. A configured client rejects unselected IDs; handler contexts accept them untyped, as the SDK defines.
  • Records holds the read and insert types: a record result's data has the read type, and create and replace take the insert type. Defaulted and generated fields are present on reads and optional on inserts, and every object level stays open to tenant-added fields. A top-level _metaData property is left out, since the SDK returns it as the result's metadata. Without a captured definition the record is Record<string, unknown>. Values in the manifest never become record types.
  • Routes and Handlers type route parameters and handler signatures. HandlerChecks verifies each referenced export against its handler type.
  • The module augments the SDK's Register with the catalog and event destinations for its TypeScript program.

Typegen checks every manifest field but types only objects, http.routes and events. Record types need an internal Object Type whose schema is an object with a declared string primary key. The record compiler supports a bounded JSON Schema subset and refuses the rest with the schema path, rather than approximating it. It does not resolve $ref. Within the subset, some rules have no TypeScript form: value constraints such as minLength, pattern and minimum keep the field's base type, and oneOf becomes a union, so a value that matches more than one alternative still type-checks. The server validates writes against the full schema.

Generated declarations

Use the pinned TypeScript 5.9.3 installed above. Merge these fields into your application's package.json:

{
  "type": "module",
  "scripts": {
    "codegen": "contextual-typegen",
    "codegen:check": "contextual-typegen --check",
    "build": "contextual-typegen && tsc -p tsconfig.json"
  }
}

Put this tsconfig.json beside contextual.yaml:

{
  "compilerOptions": {
    "target": "ES2023",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "allowArbitraryExtensions": true,
    "types": ["node"],
    "rootDir": ".",
    "outDir": "dist"
  },
  "include": ["src/**/*.ts", "contextual.d.yaml.ts"]
}

Package scripts resolve the installed contextual-typegen and tsc executables. Run npm run codegen, pnpm run codegen, or yarn run codegen to write contextual.d.yaml.ts without building. Regenerate after every manifest or lock change; the build script does this before compiling. Handler conformance errors appear in contextual.d.yaml.ts.

Commit the generated declaration if you want CI to detect stale types. Before regenerating in CI, run npm run codegen:check, pnpm run codegen:check, or yarn run codegen:check. It exits 1 if the declaration is missing or out of date. For projects that generate during every build instead, ensure codegen runs before compilation and before pruning development dependencies.

The CLI reads contextual.yaml and the optional lock from the current directory. To target another application directory, pass it as the positional argument, for example contextual-typegen ./inventory or contextual-typegen --check ./inventory from its parent.

Content mapper

The content mapper is an opt-in alternative for TypeScript 7.1.0-beta. Replace the stable compiler with that exact beta using your package manager:

npm install --save-dev --save-exact [email protected]
# or
pnpm add --save-dev --save-exact [email protected]
# or, with Yarn Classic 1
yarn add --dev --exact [email protected]

Remove contextual.d.yaml.ts and use this tsconfig.json beside contextual.yaml for type checking:

{
  "compilerOptions": {
    "target": "ES2023",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noEmit": true,
    "types": ["node"]
  },
  "contentMappers": [{ "package": "@contextual-io/typegen", "extensions": [".yaml"] }],
  "include": ["src/**/*.ts", "contextual.yaml"]
}
  • Add a package script such as "typecheck": "tsc --noEmit --runExternalCode", then run it with npm run typecheck, pnpm run typecheck, or yarn run typecheck. Without --runExternalCode, TypeScript reports TS18068 and does not run the mapper.
  • Use an editor integration that supports the TypeScript 7.1.0-beta language server and content mappers. Select that compiler for the workspace and trust the workspace to permit external mapper code. The editor must pass the equivalent runExternalCode initialization option; installing the package alone does not enable editor support.
  • The mapper starts with node from the compiler's PATH. Ensure that resolves to Node.js 24. The mapper reads the application's YAML and optional lock and emits no JavaScript.
  • The mapper reads contextual.lock.yaml from beside contextual.yaml when the project opens, reports it as a watched file and fingerprints it, so lock changes refresh --incremental builds and editor projects that deliver watched-file changes.

This configuration only checks types. Keep your application's JavaScript build separate. Content mapping does not turn YAML value imports into deployable JavaScript.

Switching modes

  • To enable the mapper, pin TypeScript 7.1.0-beta, remove contextual.d.yaml.ts so it cannot shadow the mapper, remove codegen steps and generated-file checks from your scripts, and use the mapper configuration and editor opt-in above.
  • To return to generated declarations, pin TypeScript 5.9.3, remove contentMappers and --runExternalCode, restore the generated-declaration configuration and scripts, and run codegen before compiling.

Your YAML imports can stay the same. Neither switch changes the runtime loader requirements.

Runtime loader

Type-only imports of contextual.yaml are erased and need nothing at runtime. A value import, such as objects, needs the loader:

node --import @contextual-io/typegen/register src/main.ts

The loader reads the imported contextual.yaml and its optional sibling contextual.lock.yaml. It does not read environment variables or credentials. Generating contextual.d.yaml.ts supplies types only; it does not replace the loader or create a JavaScript catalog.

For deployment, keep @contextual-io/typegen in runtime dependencies, preload @contextual-io/typegen/register, and ship the application-owned YAML and optional lock at the paths the running imports resolve to. TypeScript does not copy these files into its output directory. With the generated-declaration rootDir and outDir above, the compiled client is dist/src/main.js, so copy contextual.yaml and any contextual.lock.yaml to dist/ and start it with:

node --import @contextual-io/typegen/register dist/src/main.js

Shipping only dist/src/ will leave that value import without its manifest. If your deployment cannot use YAML or the Node hook, have your own build provide a plain JavaScript catalog and pass it through the SDK's objects option. Typegen's CLI generates declarations only; it has no JavaScript catalog generation command. Applications with only erased type imports have no YAML or loader requirement at runtime.

Troubleshooting

contextual-typegen prints manifest errors as contextual.yaml:line:column - message and lock errors as contextual.lock.yaml: message, then exits 1. The content mapper reports the same messages as diagnostics in contextual.yaml.

| Message | Cause and fix | | --- | --- | | contextual.d.yaml.ts is out of date; run contextual-typegen | --check found the file missing or different from what contextual.yaml and contextual.lock.yaml now produce. Run contextual-typegen to rewrite it. | | YAML aliases, anchors and explicit tags are unsupported | Write the value out in place of the alias, anchor or tag such as !!str. | | Prototype-sensitive keys are unsupported | Neither file accepts __proto__, constructor or prototype as a key, because converting one to JavaScript can replace an object's prototype or drop the entry. Rename the Object Type, route or event. A captured schema property with one of these names can't be typed; remove that Object Type's lock entry to type its records as Record<string, unknown>. |

Known limits with TypeScript 7.1.0-beta

  • Go to definition reaches contextual.yaml from a route parameter such as params.id and from a handler type such as Handlers["getItem"]. A string argument such as ctx.object("inventory-item") does not resolve to a definition.
  • Record fields come from the lock file, which the protocol cannot map; their definitions stay in the virtual file.
  • After contextual.yaml changes on disk, for example after a branch checkout, an editor can keep showing old errors or fail to show new ones in importing TypeScript files. The beta language server does not push the diagnostic refresh (microsoft/TypeScript#64943). Restart the workspace's TypeScript language server or reload the editor project to refresh it, and run the typecheck script for a fresh compiler result. Diagnostics requested after an unsaved YAML edit or a delivered lock-file change can already be current even while other displayed errors are stale.
  • A YAML or schema error is a mapper diagnostic, which TypeScript treats like a syntax error: other semantic diagnostics wait until it is fixed.
  • Use Node.js 24. With Node.js 22.16, the beta's tsc launcher can start the compiler with an empty environment, leaving the mapper unable to find node.