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

reearth-cms-integration-api-helper

v0.1.1

Published

Typed fetch utilities and generated types for the reearth-cms Integration REST API.

Readme

reearth-cms-integration-api-helper

TypeScript types and transport-agnostic fetch utilities for the reearth-cms Integration REST API. Both are auto-generated from server/schemas/integration/integration.yml in the reearth-cms repo.

  • Zero runtime dependencies. Works with native fetch, axios, ofetch, ky, tanstack-query, or anything else.
  • Fully typed. Every operation's path params, query, body and response body are typed off the spec.
  • Two layers:
    1. buildRequest() — returns a plain { method, url, headers, body, ... } descriptor. No HTTP call. Feed it into whatever.
    2. createClient() — convenience factory with one typed method per operationId (e.g. client.ItemCreate(...)). Uses native fetch by default, accepts a pluggable transport.

Documentation site

A VitePress site with English + 日本語 localization lives in docs/. Run it locally:

bun run docs          # dev server
bun run docs:build    # static build → docs/.vitepress/dist/
bun run docs:preview  # preview the static build

Install

bun add reearth-cms-integration-api-helper
# or
yarn add reearth-cms-integration-api-helper
# or
npm install reearth-cms-integration-api-helper

Quick start — typed client with default fetch

import { createClient } from "reearth-cms-integration-api-helper";

const cms = createClient({
  baseUrl: "https://cms.example.com/api",
  token: process.env.REEARTH_CMS_TOKEN, // -> Authorization: Bearer <token>
});

const { items } = await cms.ItemFilter({
  path: { projectIdOrAlias: "my-proj", modelIdOrKey: "posts" },
  query: { page: 1, perPage: 20 },
});

const created = await cms.ItemCreate({
  path: {
    workspaceIdOrAlias: "ws-1",
    projectIdOrAlias: "my-proj",
    modelIdOrKey: "posts",
  },
  body: { fields: [{ key: "title", value: "Hello" }] },
});

Every operationId from the OpenAPI spec is a method on the client — see src/generated/operations.ts for the full list (48 operations). Hovering cms.ItemCreate (or any op) in your editor shows the HTTP method and path, plus an @see operations.ItemCreate link that jumps into the generated schema; Go to Definition lands on the specific method in src/generated/client.ts.

Layer 1 — library-agnostic request descriptors

buildRequest(operationId, params) resolves the URL and returns a descriptor. It performs no I/O, so you can hand it to any HTTP library.

import { buildRequest } from "reearth-cms-integration-api-helper";

const req = buildRequest("ItemCreate", {
  path: { workspaceIdOrAlias: "ws", projectIdOrAlias: "p", modelIdOrKey: "m" },
  body: { fields: [] },
});
// req = {
//   method: "POST",
//   url: "/ws/projects/p/models/m/items",
//   headers: { "Content-Type": "application/json" },
//   body: { fields: [] },
//   ...
// }

Layer 2 — createClient() with a pluggable transport

The default transport uses global fetch (Node 18+, Bun, Deno, browsers, edge runtimes). To use a different library, supply a transport:

axios

import axios from "axios";
import {
  createClient,
  type Transport,
} from "reearth-cms-integration-api-helper";

const axiosTransport: Transport = async ({ baseUrl, descriptor, signal }) => {
  const { data } = await axios.request({
    baseURL: baseUrl,
    url: descriptor.url,
    method: descriptor.method,
    headers: descriptor.headers,
    data: descriptor.body,
    signal,
  });
  return data;
};

const cms = createClient({ baseUrl, token, transport: axiosTransport });

ofetch

import { ofetch } from "ofetch";
import {
  createClient,
  type Transport,
} from "reearth-cms-integration-api-helper";

const ofetchTransport: Transport = ({ baseUrl, descriptor, signal }) =>
  ofetch(descriptor.url, {
    baseURL: baseUrl,
    method: descriptor.method,
    headers: descriptor.headers,
    body: descriptor.body,
    signal,
  });

const cms = createClient({ baseUrl, token, transport: ofetchTransport });

ky

import ky from "ky";
import {
  createClient,
  type Transport,
} from "reearth-cms-integration-api-helper";

const kyTransport: Transport = ({ baseUrl, descriptor, signal }) =>
  ky(descriptor.url.replace(/^\//, ""), {
    prefixUrl: baseUrl,
    method: descriptor.method,
    headers: descriptor.headers,
    json: descriptor.body,
    signal,
  }).json();

const cms = createClient({ baseUrl, token, transport: kyTransport });

@tanstack/react-query

Use the request descriptor directly as a queryFn:

import { useQuery } from "@tanstack/react-query";
import {
  buildRequest,
  fetchTransport,
} from "reearth-cms-integration-api-helper";

function useProjects(workspaceIdOrAlias: string) {
  return useQuery({
    queryKey: ["ProjectFilter", workspaceIdOrAlias],
    queryFn: ({ signal }) => {
      const descriptor = buildRequest("ProjectFilter", {
        path: { workspaceIdOrAlias },
      });
      return fetchTransport({
        baseUrl: "https://cms.example.com/api",
        descriptor,
        signal,
      });
    },
  });
}

Or plug axios / ofetch into the queryFn the same way.

Error handling

The default transport throws HttpError for non-2xx responses:

import { HttpError } from "reearth-cms-integration-api-helper";

try {
  await cms.ProjectGet({
    path: { workspaceIdOrAlias: "ws", projectIdOrAlias: "nope" },
  });
} catch (e) {
  if (e instanceof HttpError) {
    e.status; // 404
    e.body; // parsed JSON or text response
    e.descriptor; // the request that failed
  }
}

Custom transports can throw anything they want — e.g. axios throws AxiosError.

Using from JavaScript

The package ships ESM .js + .d.ts files, so JS consumers get the same hover docs and types as TypeScript consumers. No TypeScript required:

// example.mjs
// @ts-check  ← opt into editor type-checking
import { buildRequest, createClient } from "reearth-cms-integration-api-helper";

const cms = createClient({
  baseUrl: "https://cms.example.com/api",
  token: process.env.REEARTH_CMS_TOKEN,
});

const { items } = await cms.ItemFilter({
  path: { projectIdOrAlias: "my-proj", modelIdOrKey: "posts" },
});

With // @ts-check at the top of a .js / .mjs file, VS Code (and any TS LSP) will flag bad path-param names or wrong body shapes, just like in TS.

Playground

Two runnable examples live in playground/:

bun run playground       # playground/example.ts (TypeScript)
bun run playground:js    # playground/example.mjs (JS with @ts-check)

Both import from ../src so bun runs them straight from source — no build step. Hover any identifier for types; uncomment the marked lines to see the editor surface type errors on intentionally-bad calls.

Postman collection

A ready-to-import Postman Collection v2.1 is regenerated alongside the types and committed at exports/integration.postman_collection.json.

In Postman: File → Import → Upload Files → exports/integration.postman_collection.json. Requests are organized by tag (Projects, Models, Items, Assets, …).

Version drift check

Each bun run generate bakes a sha256 of the spec contents into src/generated/version.ts. At runtime, createClient() fires a single best-effort HEAD-then-GET against the spec URL, hashes the response, and warns once per process on mismatch:

[reearth-cms-integration-api-helper] Integration API spec may be out of date.
  local  sha256: d9ad15577e5a...
  remote sha256: 3e2b8f01aa4c...
  source:        https://raw.githubusercontent.com/reearth/reearth-cms/main/server/schemas/integration/integration.yml
  Run `bun run generate` in reearth-cms-integration-api-helper to refresh the generated types.

Opt out for tests / air-gapped builds:

createClient({ baseUrl, token, skipVersionCheck: true });

Or check manually:

import {
  checkSpecVersion,
  SPEC_CONTENT_HASH,
  GENERATED_AT,
} from "reearth-cms-integration-api-helper";

const { local, remote, isLatest } = await checkSpecVersion();
if (!isLatest) console.warn("Types are behind main:", { local, remote });

The check never throws — offline / CORS-blocked requests return isLatest: true with remote: null, so nothing ever breaks because of it.

Dynamic authorization

Pass a (possibly async) function as token when the token needs to be fetched or refreshed per-request:

createClient({
  baseUrl,
  token: async () => await refreshIfNeeded(),
});

Regenerating from the spec

bun install
bun run generate

This fetches the latest integration.yml from reearth-cms/main on GitHub and regenerates:

  • src/generated/schema.ts — types
  • src/generated/operations.ts — runtime operationId → { method, path } map
  • src/generated/client.ts — per-operation ClientMethods interface with HTTP method + path in JSDoc
  • src/generated/version.ts — baked sha256 for the drift check
  • docs/public/integration.postman_collection.json — Postman Collection v2.1

All five are committed so consumers don't need to run codegen themselves. The generator throws if GitHub is unreachable — run with network access.

Release process

Releases are fully automated by GitHub Actions. As a maintainer you only ever merge PRs — version bumps, tags, npm publish, and docs deploy all happen for you.

Cutting a release manually

  1. Go to Actions → Release → Run workflow on GitHub.
  2. Pick a semver bump (patch / minor / major), or set an explicit version (e.g. 1.2.3, or 1.2.3-beta.0 for a prerelease).
  3. The workflow runs against develop, regenerates spec artifacts, bumps package.json, commits to a new release/v<version> branch, and opens two PRs: one into develop, one into main. Both are labeled release.
  4. Review and merge both PRs (order doesn't matter). Merging the main PR is what triggers publishing.

Automatic releases on spec drift

A scheduled job runs release.yml daily at 06:00 UTC:

  • It regenerates from upstream integration.yml.
  • If src/generated/ is unchanged, it exits silently.
  • If drift is detected, it cuts a patch release the same way manual dispatch does, tagging the PRs with auto-generated,spec-drift. Bump the version manually (via another dispatch) if the drift is actually breaking.

What happens after the main PR merges

  1. tag-on-main.yml sees a chore(release): v… commit on main, reads the version from package.json, and pushes tag v<version>.
  2. The tag push fans out to two workflows:
    • publish-npm.yml — reinstalls, regenerates, type-checks, builds, then npm publish --provenance. Stable versions land under the latest dist-tag; prereleases (e.g. 1.2.3-beta.0) land under a dist-tag derived from the prerelease label (beta).
    • deploy-docs.yml — builds the VitePress site and deploys it to GitHub Pages.

Prerequisites (one-time, already configured)

  • NPM_TOKEN secret with publish rights for reearth-cms-integration-api-helper.
  • GitHub Pages set to "GitHub Actions" as the source.
  • Default GITHUB_TOKEN permissions allow PR creation, tag push, and Pages deploy (granted per-workflow).

Scripts

| script | description | | --------------- | ----------------------------------------------------------------------------- | | generate | Refetch the spec and regenerate all files under src/generated/ + exports/ | | build | Emit .js + .d.ts into dist/ | | type-check | tsc --noEmit on src/ and the playground | | playground | bun playground/example.ts | | playground:js | bun playground/example.mjs | | format | Prettier over the whole package |

Package exports

// Types (from the OpenAPI spec)
import type {
  paths,
  components,
  operations, // raw openapi-typescript output
  Schemas, // alias for components["schemas"]
  Project,
  Item,
  Asset,
  GeoJSON /* ...all 24 named aliases */,
  RequestBody,
  ResponseBody, // <Op> -> JSON body types
  PathParams,
  QueryParams,
  HeaderParams, // <Op> -> param types
} from "reearth-cms-integration-api-helper";

// Runtime
import {
  createClient,
  buildRequest,
  fetchTransport,
  HttpError,
  operationsMap,
  checkSpecVersion,
  runVersionCheckOnce,
  SPEC_URL,
  SPEC_CONTENT_HASH,
  GENERATED_AT,
} from "reearth-cms-integration-api-helper";
import type {
  Client,
  ClientMethods, // per-operation method surface (source of `Client`)
  ClientOptions,
  Transport,
  TransportContext,
  RequestDescriptor,
  OperationId,
  OperationParams,
  OperationResult,
  Prettify, // flatten intersections into a single object literal
  SpecVersionResult,
} from "reearth-cms-integration-api-helper";

Source of truth

All types and the operation map descend from reearth-cms/server/schemas/integration/integration.yml. The backend consumes the same spec via oapi-codegen, so both sides stay aligned.