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

@octalmesh/seagull

v0.1.1

Published

Contract-first OpenAPI SDK, docs, and publishing pipeline - driven by a single seagull config.

Readme

Built to manage several services' contracts from one place - each service just needs an entry in the config; each artifact is generated by a reusable, shareable "recipe".

| Stage | What it does | |--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Lint | Validates every contract's OpenAPI spec for structural and style issues | | Bundle | Dereferences and bundles each spec into dist/specs | | Generate | Runs each configured "recipe" through openapi-generator-cli or openapi-typescript | | Document | Builds an interactive docs site across every contract into dist/docs | | Publish | Pushes generated SDKs to orphan git branches/tags, and to artifact registries |

flowchart LR
  A["Contract"] --> B["Lint"]
  B --> C["Bundle<br/>(spec files)"]
  C --> D["Generate<br/>(SDK artifacts)"]
  C --> E["Docs website"]
  D --> F["Publish SDK<br/>(git branch + tag)"]
  D --> G["Publish registries<br/>(npm / Maven)"]

  classDef stage fill:#363636,stroke:#666,color:#fff,rx:6,ry:6
  class A,B,C,D,E,F,G stage

This repo is a monorepo of four packages, all versioned and published together (see .changeset/config.json's fixed group and RELEASING.md). Most people only need the first one - it bundles the other three straight into its own dist/ via tsdown. The three internal packages are published independently too, for anyone who wants a smaller dependency (e.g. scripting against just @octalmesh/seagull-core's config loader without pulling in the CLI or the docs generator).

| Package | Role | |--------------------------------------------|------------------------------------------------------------------------------------------------| | @octalmesh/seagull | The seagull CLI + programmatic API. What almost everyone should install. | | @octalmesh/seagull-core | Config loading, the Generator primitive, built-in generators, version/publishing logic, etc. | | @octalmesh/seagull-cli | Pipeline commands (lint/bundle/generate/publish/...) + the commander program. | | @octalmesh/seagull-docs | Docs-site generation from bundled specs, plus a local dev server for previewing the site. |

npm install -D @octalmesh/seagull

Under the hood, generate shells out to @openapitools/openapi-generator-cli (needs a JVM on PATH) and openapi-typescript; lint/bundle and docs each rely on their own established OpenAPI tooling under the hood. All of these are @octalmesh/seagull's own dependencies, resolved via Node's module resolution.

Create a config file at the root of your contracts repo (any of .seagull, .seagull.yaml, .seagull.yml, seagull.yaml, seagull.yml):

# Seagull config version
configVersion: 1

# Custom variables to use in config
vars:
  org: "your-npm-scope"
  repository:
    owner: "your-org"
    repo: "your-contracts-repo"

# Documentation configuration
docs:
  server:
    host: "localhost"
    port: 8080

  metadata:
    title: "Your API Docs"
    description: "Generated API documentation"
    favicon: "/favicon.ico"
    baseServerUrl: "https://api.example.com"

# Publishing configuration
publishing:
  branch: "sdk/svc-{service}/{id}"
  tag: "svc-{service}-{id}-v{version}"
  repositoryUrl: "https://github.com/{vars.repository.owner}/{vars.repository.repo}"

  npm:
    registry: "https://registry.npmjs.org"
    access: "public"

  maven:
    repositoryId: "github"
    repositoryUrl: "https://maven.pkg.github.com/{vars.repository.owner}/{vars.repository.repo}"

# Generators configuration used to produce SDK artifacts
generators:
  ts-client:
    tool: "openapi-generator"
    generator: "typescript-fetch"
    lang: "typescript"
    kind: "client"
    package: "@{vars.org}/{service}-client"

# Per-service contract configuration
contracts:
  - name: "auth"
    title: "Auth Service API"
    entrypoint: "specs/auth/openapi.yaml"
    artifacts:
      - "ts-client"

Then:

npx seagull lint
npx seagull bundle
npx seagull generate
npx seagull docs generate && npx seagull docs serve

See examples/ for complete, runnable configs covering every generator/publishing/docs feature, plus an API walkthrough.

  • configVersion: (required) - which version of the config schema this file targets. Decoupled from @octalmesh/seagull's own npm version on purpose: this only changes if seagull.yaml's shape changes in a breaking way, so an old config fails with a clear "expected configVersion 1" error.

  • generators: - reusable recipes: a tool (openapi-generator or openapi-typescript), which -g template to use, and naming templates for the npm package / Go module / Maven coordinates. Any string field may reference {vars.some.nested.key} or {service} (the current contract's name).

  • contracts: - one entry per service (name, title, entrypoint, and which generators: it wants under artifacts:, by id). Two services don't need the same generators - a contract can reference a generator with a per-contract override instead of duplicating the whole recipe:

    contracts:
      - name: "payment"
        artifacts:
          - generator: "java-client"
            as: "java-client-legacy" # renames this artifact's output folder/branch/tag
            overrides:
              generator: "java-legacy-template"
              additionalProperties:
                library: "jersey2"
  • vars: - a free-form tree for anything used in naming templates. Nest however deep is useful; every leaf is addressable as {vars.a.b.c}.

  • paths: - only dist: is required; specs/docs/sdk default to <dist>/specs, <dist>/docs, <dist>/sdk and only need to be set to override that. specFormat: controls what format(s) seagull bundle writes specs in - json (default), yaml, or a list of both (specFormat: [json, yaml]) to bundle into more than one format at once; Redocly infers the output format from the file extension on its own, so this is a free choice, not a compatibility trade-off. When more than one format is configured, the first one listed is the "primary" format SDK generation and the docs site actually read from - the rest are bundled as additional static artifacts alongside it.

  • docs: - server: { host, port } for docs serve, and metadata: { title, description, favicon, baseServerUrl } for the generated docs site.

  • publishing: (required) - see below.

A typo or missing field fails immediately with a readable, path-annotated error. Config is validated on every run.

seagull.yaml (and redocly.base.yaml) also support the YAML <<: *anchor merge key, so shared fields don't need to be repeated across every entry:

_defaults: &defaults
  lang: "typescript"

generators:
  ts-server:
    <<: *defaults
    tool: "openapi-typescript"
    kind: "server"
    package: "@{vars.org}/{service}-server"

  ts-client:
    <<: *defaults
    tool: "openapi-generator"
    generator: "typescript-fetch"
    kind: "client"
    package: "@{vars.org}/{service}-client"

publishing: controls where things get published to - git branch/tag naming, and npm/Maven registry URLs. It's required at the root level: seagull has no built-in convention here, so a config that omits it fails validation with a message pointing at exactly what's missing, rather than silently applying an opinionated default nobody chose.

publishing:
  branch: "sdk/svc-{service}/{id}"                                                   # git branch each artifact publishes to
  tag: "svc-{service}-{id}-v{version}"                                               # git tag - the only field where {version} is available
  repositoryUrl: "https://github.com/{vars.repository.owner}/{vars.repository.repo}" # git remote URL for pushing branches/tags

  npm:
    registry: "https://npm.pkg.github.com"
    access: "restricted" # or "public"

  maven:
    repositoryId: "github"
    repositoryUrl: "https://maven.pkg.github.com/{vars.repository.owner}/{vars.repository.repo}"

Every field is a template - the same {...} engine as naming templates, plus {id} (the artifact's id) and, for tag only, {version} (resolved once the contract's spec is bundled, since a branch is created before a version is known but a tag isn't).

Like additionalProperties and readme, publishing: can be overridden per-generator (generators.<id>.publishing) or per-contract-artifact (artifacts[].overrides.publishing) - only the fields that differ need repeating, the rest fall through to the root-level config:

flowchart TD
  A["Root config<br/>(fallback for everything)"] --> B["Generator override<br/>(per recipe)"]
  B --> C["Artifact override<br/>(per contract)"]
  C --> D(["Effective config<br/>for this artifact"])

  classDef layer fill:#363636,stroke:#666,color:#fff,rx:6,ry:6
  classDef result fill:#1f6feb,stroke:#1f6feb,color:#fff,rx:20,ry:20
  class A,B,C layer
  class D result

The same three-layer precedence (root -> generator -> artifact overrides) applies to additionalProperties and readme too, not just publishing.

generators:
  ts-client:
    # ...
    publishing:
      npm:
        registry: "https://registry.internal.example.com" # every contract's ts-client uses this registry

contracts:
  - name: "payment"
    artifacts:
      - generator: "ts-client"
        overrides:
          publishing:
            branch: "custom/{service}-{id}-branch" # ...except payment's ts-client, which also uses a different branch

Every generated artifact gets a README.md - by default a sensible built-in template for its language/kind. To use your own, point readme: at a template file (path relative to the config file):

generators:
  ts-client:
    # ...
    readme: "readme-templates/ts-client.md"

Template files support the same {...} placeholders as naming templates, plus a few more:

| Placeholder | Value | |------------------------------------------------------------|--------------------------------------------------| | {service} | The contract's name | | {title} | The contract's title | | {version} | The resolved SDK version | | {vars.*} | Anything under vars: | | {artifact.id} | The artifact's id (as listed under artifacts:) | | {artifact.package} | Resolved npm package name (TypeScript) | | {artifact.goModule} / {artifact.goPackageName} | Resolved Go naming | | {artifact.maven.groupId} / {artifact.maven.artifactId} | Resolved Maven coordinates | | {artifact.branch} / {artifact.tag} | Resolved publishing branch / tag | | {artifact.npmRegistry} / {artifact.mavenRepositoryUrl} | Resolved registry URLs from publishing: |

An unresolvable placeholder fails the build loudly (a typo'd {vesion} won't silently ship as literal text).

seagull lint                           Lint every contract's OpenAPI spec
seagull bundle                         Bundle every contract's spec into dist/specs
seagull generate                       Generate every configured SDK artifact into dist/sdk
seagull clean                          Remove the dist directory
seagull docs generate                  Generate the documentation site into dist/docs
seagull docs serve                     Serve the generated documentation site locally
seagull publish sdk [--dry-run]        Publish generated SDKs to their git branches/tags
seagull publish registries [--dry-run] npm publish / mvn deploy the registry-backed artifacts

Every command accepts -c, --config <path> to point at a config file outside the current directory.

pnpm install       # install dependencies for all packages
pnpm run build     # builds packages/* first (topological), then bundles the root package
pnpm run typecheck # run after build - resolves the workspace packages via their built dist/
pnpm run lint      # lint all packages
pnpm run test      # run all tests

See CONTRIBUTING.md for how to propose changes, and RELEASING.md for how versioning and publishing work.