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

@200stack/static-forms-core

v0.2.4

Published

Shared Static Forms build contract schemas and canonical digest utilities.

Readme

@200stack/static-forms-core

Shared Static Forms build contract primitives for later Dashboard, framework adapter, and build-runtime slices.

This package currently includes:

  • strict Zod schemas and inferred TypeScript types for adapter probe results, materialization refs, framework adapter metadata, slot render targets, and build manifests
  • strict Zod schemas and inferred TypeScript types for StaticFormDefinitionV1, StaticFormConditionAstV1, client-safe StaticFormRenderTreeV1, StaticFormBuildSnapshotV1, and StaticFormAdapterProofV1
  • shared validation for text, email, textarea, select, radio, single-consent checkbox, multiple-choice checkboxes, tel, url, date, and number fields
  • deterministic Definition to RenderTree compilation
  • a deterministic reference HTML renderer for semantic fragments
  • a minimal client state machine and submission validator
  • Draft 2020-12 structural JSON Schema exports generated from the implemented Zod schemas with Zod 4 native z.toJSONSchema()
  • a versioned, limited canonical JSON serializer for JSON-compatible values
  • a Node build-time SHA-256 digest helper for canonical JSON bytes, exported only from @200stack/static-forms-core/node

checkboxes(複数選択)は選んだ値を配列で送ります。0.2.3 以上の adapter と build protocol v2 が要ります。 tel・url・date・number は 0.2.4 以上の adapter と build protocol v2 が要ります。

This package intentionally does not change Dashboard, build-runtime, forms-worker, DB, API, UI, Worker, or Cloudflare behavior.

The Definition contract is intentionally limited to the Phase 1a public/client-safe slice. Mail templates, security policy, and integrations are exported only as id/version/digest references; provider configuration, recipients, secrets, template bodies, attachment processing, D1/R2/Queue behavior, Dashboard APIs, and framework adapters remain outside this package.

Consumers should treat this package as the shared wire contract source of truth. Dashboard can validate publish-time definitions and manifests, adapters can validate their metadata and slot targets, build-runtime can accept only materialization refs/manifests/snapshots that parse through these schemas, and Workers can reuse the same field validator.

Client/server split

The root export and @200stack/static-forms-core/schema, @200stack/static-forms-core/json-schema, @200stack/static-forms-core/canonical-json, and @200stack/static-forms-core/core are browser and Cloudflare Worker safe. They do not import node:crypto.

Node-only SHA-256 helpers live under @200stack/static-forms-core/node. Build-time callers can combine that subpath with canonicalJsonStringify() to compute digests. Worker/browser callers should provide their own runtime-appropriate digest implementation if they need hashing.

0.2.4 の変更

フィールドの種類に、電話番号 tel・URL url・日付 date・数値 number を足しました。値はどれも文字列です。

  • tel: 半角の数字と + - ( ) 空白だけ、数字は 6〜15 桁、32 文字まで。
  • url: http: か https: でホストがあるもの、空白・制御文字なし、2048 文字まで。
  • date: 実在する YYYY-MM-DD(1900〜2100 年)。validation.min / max で範囲を指定できます(範囲外は too_early / too_late)。
  • number: 10 進の数(整数部と小数部を合わせて 15 桁、小数は 6 桁まで)。validation.min / max / integer を指定できます(範囲外は too_small / too_large)。入力欄は type="text" と inputmode です。
  • 形が合わないときのエラーコードは invalid_format です。
  • controller は電話番号・数値の全角の数字と記号を半角に直して確認・送信します。日付を途中まで入れた欄は invalid_format で止めます。
  • build protocol v2 だけで使えます(v1 ではビルドを止めます)。0.2.3 以前の adapter・core はこの 4 つを含むフォームを読めないため、使うときは adapter を 0.2.4 に上げてください(adapter 0.2.4 は core 0.2.4 を使います。core 0.2.3 は公開していません)。今の種類の動きは変わりません。

0.2.2 の変更

フィールドの種類に、複数選択のチェックボックス checkboxes を足しました。選択肢を並べ、選んだ値を配列で送ります。必須(1 つ以上)と、選べる数の下限・上限(validation.minSelected / maxSelected)を指定できます。確認画面とメールでは、選んだ選択肢の名前を「、」でつないで出します。build protocol v2 だけで使えます(v1 ではビルドを止めます)。0.2.2 以前の adapter は checkboxes を含むフォームを読めないため、使うときは adapter を 0.2.3 に上げてください(adapter 0.2.3 は core 0.2.2 を使います)。今の種類の動きは変わりません。

0.2.1 の変更

v2 と開発表示のプライバシーの案内のリンク(flow.privacy)は、別のタブで開きます(target="_blank" rel="noopener noreferrer")。入力の途中でポリシーを開いても、書きかけは消えません。別のタブで開くことは、リンクの中の読み上げだけの添え書き(data-200stack-static-form-new-tab。見た目には出さない)で伝えます。ビルド入力・schema・controller は 0.2.0 と同じです。

0.2.0 の変更

完了後の移動先はサイト内のルートからのパスだけです。@200stack/static-forms-core/browser の isSafeRedirect() は、2,048 字以内で / から始まるパスを検証します。//・絶対 URL・バックスラッシュ・空白や制御文字・#・パスの .. 区間・エンコードされた . / / / バックスラッシュは拒否します。クエリは使えます。controller は移動先の origin も確認します。

受付を確認すると、フォームのルートから STATIC_FORM_ACCEPTED_EVENT (200stack-static-form:accepted) を通知します。bubbles: true・cancelable: false の CustomEvent で、StaticFormAcceptedEventDetail は凍結した { slotId?: string, publicFormId: string, instanceId: string } です。メッセージを表示した後、または移動を呼ぶ前に通知し、入力値や受付 ID は含めません。同じ controller の同じ送信で最大 1 回通知します。定数と型は root・/core・/browser から export し、ブラウザのコードでは /browser を使ってください。

フォームの定義と render tree は lang: 'ja' | 'en' を持てます。resolveStaticFormLang(tree, optionLang?) は定義の言語を使い、定義に無ければ adapter の指定、両方無ければ日本語を使います。定義と異なる指定は StaticFormLangMismatchError になります。staticFormLanguages は対応する言語、staticFormLanguageNames は表示名です。これらは root と /core から export します。v2 と開発表示は解決した言語で固定文と検証エラーを表示します。項目名など保存済みの文言は自動翻訳しません。v1 は従来の英語固定です。

StaticFormDeliveryPlanV1.destinations は、運営者への ses_owner_email 1 件、またはその後に送信者への ses_submitter_auto_reply 1 件を加えた tuple の union です。自動返信は recipientFieldName で返信先の項目を指定し、固定テンプレートに入力値の変数を含めません。運営者のテンプレートは {{display.<fieldName>}} を使えます。definition を渡すと、select・radio は選択肢のラベル、チェック済み checkbox は同意文、その他は入力値になります。非表示・未入力・存在しない項目は空文字です。fields.* は従来の値を使い、HTML の置換値はエスケープします。renderStaticFormDeliveryPlan() は運営者の 1 件だけを返します。自動返信の描画や配送をこの関数に任せないでください。

v2 の renderStaticFormReferenceHtml() は slotId を指定するとルートに data-200stack-static-form-slot 属性を出し、受付イベントの detail.slotId に使います。未指定や旧い HTML ではイベントのキーを省略します。v1 と開発表示にはこの属性を出しません。

0.1.0 は 0.2.0 のビルド入力を読めません。新しい入力を使うサイトは core・SDK・adapter を対応する版に更新し、サイトを再ビルドしてください。

Determinism and reference rendering

compileStaticFormRenderTreeV1() is a pure compiler from a parsed Definition plus caller-provided digests/assets to a client-safe render tree. It does not read the clock, generate random values, or include absolute paths. Snapshot objects do not self-embed snapshotSha256 or generatedAt.

StaticFormDefinitionV1 uses the Phase 1a wire contract from the ExecPlan: renderer.accentToken, flow.confirmation as none | generated | configured(title, description?, submitLabel?), flow.completion as message or redirect, scrollBehavior as none | form | message, and runtime callback names such as beforeConfirm / beforeSubmit. publicFormId is intentionally not part of Definition or RenderTree; it belongs to snapshot slots and render options.

renderStaticFormReferenceHtml() renders a deterministic semantic <section><form>... fragment from a render tree and caller-provided publicFormId/instanceId. Message completion renders a hidden completion subtree with escaped title/body. Redirect completion is not converted into an arbitrary message. The renderer exists for conformance fixtures, previews, and simple static targets such as Eleventy. It is not a post-build DOM mutation tool and is not a replacement for framework adapter templates.

Adapter proof semanticDomDigest values are SHA-256 digests of this core reference HTML fragment for the occurrence. They are not digests of the framework-native output DOM. Framework adapters must still prove native output parity separately; semanticDomVerified: false remains the build-runtime posture until a native DOM verification step exists.

Definitions and render trees do not accept raw HTML, arbitrary CSS/class/style, JavaScript, event handlers, selector maps, or user-supplied tag/attribute maps. Text is plain text and the reference renderer escapes text and attributes before output.

Validation boundary

Exports whose names end in StructuralJsonSchema reject unknown object properties and enforce the constraints that Draft 2020-12 can represent. They are not a replacement for the corresponding Zod parser. superRefine invariants such as default-target membership, unique target/slot IDs, and slot target allowlists are semantic checks and require Zod parsing (or an equivalent implementation in another language) before wire input is accepted. Safe R2 object-key syntax is encoded in both Zod and the structural JSON Schema pattern.

StaticFormPublicId has an opaque-token-compatible wire shape of 22 to 128 base64url characters. The future generator remains responsible for using a cryptographically secure source with at least 128 bits of randomness; parsing a string cannot prove its entropy.

Canonical JSON v1

canonicalJsonStringify() is the algorithm identified by STATIC_FORM_CANONICAL_JSON_VERSION = 1; it does not claim RFC 8785 compatibility. It accepts only data properties containing JSON-compatible values, sorts object keys with JavaScript's default UTF-16 code-unit ordering, preserves array order, serializes finite numbers and strings with JSON.stringify, and performs no Unicode normalization. The Node helper hashes the resulting UTF-8 bytes with SHA-256. Non-JavaScript adapters must match the package's golden vectors before they can emit compatible digests.

見た目を指定する(v2)

StaticFormStyle はクラス名の文字列だけを受け取ります。項目の指定は field → 種類 (text / email / textarea / select / radio / checkbox / checkboxes / tel / url / date / number) → byName[name] の順に連結します。この順は CSS の優先順位を保証しません。未知の byName は警告し、種類に合わない部品は警告して使いません。

const style = {
  section: { title: 'text-xl font-bold' },
  field: { root: 'mb-5', label: 'font-medium', error: 'text-rose-600' },
  email: { control: 'rounded border aria-[invalid=true]:border-rose-600' },
  radio: { group: 'grid gap-2', option: 'flex gap-2', input: 'size-4' },
  byName: { email: { label: 'text-indigo-800' } },
} satisfies StaticFormStyle

| style のキー | part の正確な値 | 本番の DOM | 開発の表示 | | --- | --- | --- | --- | | root | root | section[data-200stack-static-form] | 外側の div[role=form] (root form) | | form | form | form | 外側の div[role=form] | | section.root / .title / .description | section / section-title / section-description | section / h2 / p | 同じ | | field.root | field | 項目の外枠 div | 同じ | | *.label / .description / .error | label / description / error | label または legend / p / p | 同じ | | text・email・textarea・select・tel・url・date・number .control | control | input / textarea / select | 同じ | | radio・checkbox・checkboxes .group / .option / .input | group / option / input | fieldset / 選択肢 label / input | 同じ | | formErrors / status | form-errors / status | 全体エラー / 状態の div | 出ない | | privacy.root / .link | privacy / privacy-link | p / a | 同じ | | submit | submit | 送信 button | 無効の button | | confirmation.* | confirmation、confirmation-title、confirmation-description、confirmation-list、confirmation-item、confirmation-label、confirmation-value、confirmation-back、confirmation-send | div / h2 / p / dl / div / dt / dd / buttons | 出ない | | completion.* | completion、completion-title、completion-body | div / h2 / p | 出ない |

条件で DOM が出ない部品には効果がありません。特に、render tree で consentText が無い checkbox には group と label がありません。theme.css と公開の目印は v2 と開発表示だけで、v1 の出力には効きません。制御文字、JSON 全体 32 KiB、合成済み class 属性 2,000 バイトを超えるとエラーです。Tailwind は完全なクラス名をソースに書き、v3 は content、v4 は @source に共有 style ファイルを含めます。動的なクラスは検出されず、エラー用には aria-[invalid=true]:border-rose-600 のように書きます。

CSS の目印と theme.css

v2 本番と開発表示で公開する目印は、各部品の data-200stack-static-form-part、項目外枠の data-200stack-static-form-type・-name・-required・-invalid です。複数の役割は空白区切りなので [data-200stack-static-form-part~="form"] のように ~= を使います。name は .・: を含み得るため引用符で囲み、name を変更すると name を狙う CSS と byName は黙って外れます。controller 実行時の要素と開発表示の説明文は公開契約外です。HTML は項目ごとに 100〜200 バイト、選択肢ごとに約 70 バイト増えます。

adapter の theme は Next で import '@200stack/static-forms-next/theme.css'、Astro で import '@200stack/static-forms-astro/theme.css'、Eleventy で theme: true と {% staticFormsTheme %} を使います。--200stack-sf-accent、--200stack-sf-accent-hover、--200stack-sf-text、--200stack-sf-muted、--200stack-sf-border、--200stack-sf-frame-border、--200stack-sf-error、--200stack-sf-error-text、--200stack-sf-radius、--200stack-sf-surface、--200stack-sf-error-surface、--200stack-sf-on-accent、--200stack-sf-completion-surface、--200stack-sf-completion-text を上書きできます。

@layer static-forms;
[data-200stack-static-form-part~="root"] { --200stack-sf-accent: #0f766e; --200stack-sf-surface: #06251f; --200stack-sf-text: #ecfdf5; }

一般のサイトは CSS の先頭に @layer static-forms; を置きます。レイヤー外の CSS と後ろのレイヤーの CSS が勝ちます。Tailwind v4 は @layer theme, base, static-forms, components, utilities; を @import "tailwindcss"; より前に置き、theme.css は layer() を付けずに読み込みます。Astro は既定で小さな CSS を inline にするため、厳しい CSP では build.inlineStylesheets: 'never' にしてください。

theme.css だけの本番は style-src 'self'(または配信元)で足りますが、v2 は固定の <style> を常に出します。本番は 'sha256-LE3mSYpIJxrT67iqOfLXzAcqron3YCrRA+rogsSVPYA='、開発表示は 'sha256-PooA9aoFhckRsEL2CK2Uxp0tODRwW2JydE6jQ+WgQ+M=' を style-src(指定時は style-src-elem にも)へ追加してください。開発表示の重複診断 style は出力ごとの hash が必要です。

0.1 からの移行

| 0.1 | 0.2 | | --- | --- | | 平たい label / description / error | field.label / .description / .error | | 平たい input / textarea / select | text 系の .control | | fields.* / types.* の input | text 系は .control、radio・checkbox は .input | | 文字列の field / section / confirmation / completion | それぞれの .root | | choiceGroup / choiceLabel / radio / checkbox | choice の .group / .option / .input | | sectionTitle / sectionDescription | section.title / .description | | confirmationList など | confirmation.list など | | types / fields | 種類キー / byName | | first / last | section 内の表示位置は CSS、特定項目は byName |

StaticFormElementClasses・StaticFormFieldClasses は削除済みで、項目の型は StaticFormFieldStyle です。旧キーは読み替えず、Static Forms style uses 0.1 key at fields.email; see README: Migrating from 0.1 のようにエラーになります。