This doc is for people working on meander itself, not consumers using it.
- Node >= 24 (the
enginesfloor;.node-versionpins the exact dev version). - pnpm 11+.
pnpm install
pnpm build # tsc emits dist/| Command | What it does |
|---|---|
pnpm dev |
Generate the fixture and serve it at http://127.0.0.1:8080 with file-watcher. |
pnpm test |
Run the vitest suite under test/ (val runtime tests included). |
pnpm cover |
vitest + type-coverage, prints a combined summary. |
pnpm check |
lint + type-check (what CI runs). |
pnpm fix |
oxfmt + oxlint --fix; mutates files in place. |
pnpm clean |
Remove dist/, coverage/, fixture emit dirs. |
pnpm build |
tsc; emits .mjs + .d.mts to dist/. |
- Tests live in
test/**/*.test.mts. - Fixtures live in
test/fixtures/. The reference fixture,test/fixtures/test-docs/, also powerspnpm devand the CI smoke test. - Config is at
.config/repo/vitest.config.mts. Coverage provider is v8, report-only: nocover.thresholdsare configured in.config/repo/socket-wheelhouse.json, sopnpm coverprints the summary without gating. - Need a scratch directory? Use
mkdtempSync(path.join(os.tmpdir(), '…'))+safeDeletefrom@socketsecurity/lib/fsinafterEach. Never write into the repo tree.
The val (assets/val/index.ts) runs under Deno at Val Town.
Its pure helpers (crypto, JWT, auth-domain matching) live in
assets/val/lib/*.ts and are tested by the vitest suite in
test/val/, which runs with pnpm test. Web Crypto is
available in both Deno and Node so the helpers behave
identically; tests don't mock anything.
The val's HTTP routes - the Hono app + blob/sqlite interactions -
are not unit-tested; they're exercised end-to-end by
meander deploy-val against a staging val and the human
sign-in flow. If a future route changes pull logic out of the
request handler, move that logic into lib/ too and test it
there.
.github/workflows/ci.yml- lint + type-check + smoke test- full test suite with coverage.
.github/workflows/pages.yml- builds the fixture under--base-path=/meanderand deploys it tohttps://socketdev.github.io/meander/as a live demo.
Keep every action ref pinned to a full commit SHA, not a tag, per the fleet security policy.
oxfmt + oxlint enforce style. Relevant settings that aren't obvious from looking at a diff:
- Single quotes for strings.
- No semicolons (ASI).
- Arrow parens avoided when safe (
x => x.id). - Trailing commas everywhere they're valid.
- Type imports as separate
import typestatements, never inlinetypein value imports.
Browser scripts under assets/*.js are a separate world:
-
ES5-compatible (
var,function, classic for-loops). -
Wrapped in an IIFE with
"use strict";at the top. -
DOMContentLoaded guard pattern:
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init) } else { init() }
src/cli.mts- argv parser + command dispatcher.src/generate.mts- HTML emission + annotation pipeline.src/config.mts- single-source schema (TypeBox) + loader.src/serve.mts- local preview server.src/publish.mts- encrypt + upload to Val Town.src/deploy-val.mts- one-shot val deploy.src/crypto.mts- AES-256-GCM + PBKDF2 helpers.src/classifiers.mts- inline<code>shape predicates.src/minify.mts,src/security.mts,src/prose-polishers.mts,src/render-mermaid.mts,src/url-rewrite.mts- emit-time passes applied bygenerate.assets/val/index.ts- the deployed Hono handler.
- Conventional Commits format:
<type>(<scope>): <description>. - No AI attribution in commit messages.
- No customer names or issue-tracker IDs (
SOC-123, Linear URLs, etc.) in code, commits, or PRs. - Breaking config-schema changes need a major version bump and a migration note.