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

@sharedan/cms-sdk

v0.4.1

Published

TypeScript SDK for the ShareDan 簡易CMS public API — posts (by post type), post types, FAQs, static contents, categories, and form delivery/submission (with spam protection).

Readme

@sharedan/cms-sdk

ShareDan CMS の公開API を扱う TypeScript SDK です。 投稿(種別ごと)・FAQ・固定コンテンツ・カテゴリの取得、本文(ProseMirror / Tiptap JSON)の HTML レンダリング、およびフォームの配信・送信(スパム対策込み)を、型付き・依存ゼロで提供します。 ブラウザと Node.js 18+ の両方で動作します。

投稿は「種別(post type)」でスコープします。 投稿系メソッドは第1引数に種別のslug (既定種別は 'news')を取ります(例 cms.posts.list('news'))。利用可能な種別は cms.postTypes.list() で取得できます。

特長

  • 🧩 型付きクライアント — 各エンドポイントを cms.posts / cms.postTypes / cms.faqs / cms.contents / cms.forms / cms.maintenance で呼び出し、レスポンスは完全に型付け
  • 🖋️ リッチテキスト対応 — 本文/回答の ProseMirror JSON を renderProseMirror() で HTML 文字列へ変換
  • 📨 フォーム送信 — 問い合わせ等フォームの配信(項目定義)と送信を cms.forms でラップ。Turnstile・レートリミット・ハニーポット・送信速度・重複防止の多層スパム対策に対応
  • 🚦 明快なエラー型ShareDanCmsApiErrorstatus / code / isNotFound / isRateLimited 等)と ShareDanCmsNetworkError
  • 📦 依存ゼロ・軽量fetch ベース。ブラウザ / Node / エッジランタイムで動作
  • 🔒 主に閲覧専用 — 公開API(X-API-KEY でテナント、X-SITE-CODE でサイトを特定)をラップ。書き込みはフォーム送信(cms.forms.submit)のみ

インストール

npm install @sharedan/cms-sdk

リポジトリを直接クローンして使う場合は、npm install 後に npm run builddist/(ESM + 型定義)を生成してから読み込んでください。

クイックスタート

import { ShareDanCmsClient, renderProseMirror } from '@sharedan/cms-sdk'

const cms = new ShareDanCmsClient({
  baseUrl: 'https://cms.example.com', // CMSのオリジン(/api/v1 は自動付与)
  apiKey: 'YOUR_API_KEY',             // X-API-KEY
  siteCode: 'your-site',              // X-SITE-CODE
})

// 種別一覧(discovery。既定種別は slug 'news')
const { items: postTypes } = await cms.postTypes.list()

// 投稿一覧(種別 'news'・カテゴリ絞り込み・ページネーション)
const news = await cms.posts.list('news', { category: 'event', page: 1, perPage: 20 })
console.log(news.meta.total, news.items)

// 投稿詳細(本文あり)→ HTML 化
const detail = await cms.posts.get('news', news.items[0]!.slug)
element.innerHTML = renderProseMirror(detail.body)

// FAQ / 固定コンテンツ / カテゴリ(投稿カテゴリは種別スコープ)
const faqs = await cms.faqs.list({ category: 'product' })
const content = await cms.contents.get('top-message')
const categories = await cms.posts.categories('news')

設定

| オプション | 必須 | 説明 | |-----------|:---:|------| | baseUrl | ✓ | CMSのオリジン(例 https://cms.example.com)。/api/v1 は自動付与 | | apiKey | ✓ | テナントのAPIキー(X-API-KEY) | | siteCode | ✓ | サイト識別子(X-SITE-CODE / m_sites.code) | | apiVersion | | APIバージョン(既定 'v1') | | fetch | | 使用する fetch 実装(既定 globalThis.fetch) | | timeoutMs | | タイムアウト(ミリ秒)。AbortController で中断 | | headers | | 全リクエストに付与する追加ヘッダ |

API

| メソッド | エンドポイント | 戻り値 | |---------|---------------|--------| | cms.postTypes.list() | GET /api/v1/post-types | ListResponse<PostTypeSummary> | | cms.posts.list(postType, params?) | GET /api/v1/posts/{postType} | Paginated<PostSummary> | | cms.posts.get(postType, slug) | GET /api/v1/posts/{postType}/{slug} | PostDetail | | cms.posts.getPreview(postType, slug, token) | GET /api/v1/posts/{postType}/{slug}/preview | PostDetail(下書き版・X-PREVIEW-TOKEN・非キャッシュ) | | cms.posts.categories(postType) | GET /api/v1/posts/{postType}/categories | ListResponse<Category> | | cms.faqs.list(params?) | GET /api/v1/faqs | ListResponse<Faq> | | cms.faqs.categories() | GET /api/v1/faqs/categories | ListResponse<Category> | | cms.contents.get(key) | GET /api/v1/contents/{key} | Content | | cms.forms.get(key) | GET /api/v1/forms/{key} | Form(項目定義・非キャッシュ) | | cms.forms.submit(key, input) | POST /api/v1/forms/{key}/submissions | FormSubmissionResult | | cms.maintenance.get() | GET /api/v1/maintenance | Maintenance(非キャッシュ) |

postType は種別のslug(既定種別は 'news')。存在しない種別は 404 になります。

PostDetail.body / Faq.answer / Content.body は ProseMirror JSON(ProseMirrorNode)です。 PostDetail.metaPostMeta)にはメタタイトル・ディスクリプション・OGP画像URL(meta_title / meta_description / og_image_url)が入り、公開ページのSEO/OGP出力に使えます(未設定時は null)。

フォーム(配信・送信)

cms.forms.get(key) でフォームの項目定義(fields)と、Turnstile 設定・送信速度チェック用トークン(speed_check_token)を取得し、cms.forms.submit(key, input) で送信します。

// 1. 配信:項目定義とトークンを取得(都度発行のためキャッシュ不可)
const form = await cms.forms.get('contact')

// 2. 送信:各項目 name をキーに値を渡す
const result = await cms.forms.submit('contact', {
  values: {
    name: '山田 太郎',
    email: '[email protected]',
    message: '製品について問い合わせたいことがあります。',
  },
  // 送信速度チェックが有効なフォームでは、配信で受け取ったトークンをそのまま返す
  speedCheckToken: form.speed_check_token,
  // Turnstile 有効フォームでは、ウィジェットが発行したトークンを渡す
  turnstileToken: form.turnstile.enabled ? widgetToken : undefined,
})
console.log(result.id, result.submitted_at)
  • スパム対策(Turnstile/レートリミット/ハニーポット/送信速度/重複送信)はサーバ側で適用されます。ハニーポット項目は SDK が空値で自動付与します。
  • ファイル項目(type: 'file' は値に FileBlob を渡します。File/Blob を含む送信は自動で multipart/form-data になり、ファイルはサーバ側でS3に保存されます(送信データにはファイル参照が格納されます)。1ファイル最大10MB/許可形式は画像・PDF・Word・Excel・テキスト。
  • Turnstile 有効時は form.turnstile.site_key でフロントにウィジェットを描画し、得たトークンを turnstileToken に渡してください(secret_key はAPIから返りません)。

メンテナンス状態

cms.maintenance.get() でサイトのメンテナンス状態を取得します。投稿・FAQ 等の利用コンテンツ設定に関わらず常に応答し、状態を即時反映するためキャッシュされません(表示のたびに取得してください)。

const status = await cms.maintenance.get()
if (status.maintenance) {
  // メンテナンス中:見出し・案内・再開予定を表示
  console.log(status.title, status.message, status.resumes_at)
} else {
  // 通常表示
}

maintenance を判別子とする直和型(Maintenance)です。maintenance: false のときは他のフィールドを持ちません。

リッチテキストのレンダリング

import { renderProseMirror, extractText } from '@sharedan/cms-sdk'

const html = renderProseMirror(detail.body)             // HTML文字列
const html2 = renderProseMirror(faq.answer, {           // リンク属性のカスタマイズ
  linkTarget: '_self',
  linkRel: null,
})
const excerpt = extractText(detail.body).slice(0, 120)  // プレーンテキスト抜粋

対応ノード: paragraph / heading / bulletList / orderedList / listItem / taskList / taskItem / blockquote / codeBlock / horizontalRule / hardBreak / image / fileAttachment 対応マーク: bold / italic / underline / strike / code / textStyle(文字色) / highlight(ハイライト) / link

React などで使う場合は、出力を dangerouslySetInnerHTML に渡すか、renderProseMirror を参考に独自レンダラを実装してください。

エラーハンドリング

import { ShareDanCmsApiError, ShareDanCmsNetworkError } from '@sharedan/cms-sdk'

try {
  const content = await cms.contents.get('top-message')
} catch (err) {
  if (err instanceof ShareDanCmsApiError) {
    if (err.isNotFound) { /* 404: 未存在/利用しない設定 */ }
    console.error(err.status, err.code, err.details)
  } else if (err instanceof ShareDanCmsNetworkError) {
    // 接続不可・タイムアウト・CORS など
  }
}

フォーム送信では、スパム対策・バリデーションの結果を判定できます。

try {
  await cms.forms.submit('contact', { values, speedCheckToken: form.speed_check_token })
} catch (err) {
  if (err instanceof ShareDanCmsApiError) {
    if (err.isBadRequest) { /* 400: Turnstile検証失敗など */ }
    if (err.isValidationError) { /* 422: 入力不正・ハニーポット・送信速度・重複送信 */ }
    if (err.isRateLimited) {
      // 429: レート制限。err.retryAfter 秒後に再試行
      console.warn('retry after', err.retryAfter, 'seconds')
    }
  }
}

開発

npm install       # typescript を取得
npm run build     # dist/ に ESM + 型定義を出力
node examples/node.mjs   # ローカルCMS(http://localhost:8091)に対するスモークテスト

ライセンス

MIT © ShareDan CO. ,Ltd.