diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a71e14e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,28 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. + +## Our Standards + +Examples of behavior that contributes to a positive environment include welcoming language, respectful communication, and constructive feedback. + +Examples of unacceptable behavior include harassment, trolling, and publishing others' private information. + +## Enforcement Responsibilities + +Project maintainers are responsible for clarifying and enforcing our standards. + +## Scope + +This Code of Conduct applies within all community spaces and in public when an individual is officially representing the project. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the maintainers. +The maintainers will review and respond as appropriate. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..356ee03 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing to @sigrea/react + +Thank you for contributing! This project uses a PR-based workflow with required CI checks. + +## Requirements + +Node.js >= 20 and pnpm >= 10. +TypeScript strict mode, Biome for formatting, Vitest for tests. + +## Scripts + +`pnpm typecheck` — run TypeScript checks +`pnpm test` — run unit tests +`pnpm build` — build the library via unbuild +`pnpm format` — check formatting (no writes) +`pnpm format:fix` — apply formatting + +## Commit Convention + +Conventional Commits are required. Examples: `feat: ...`, `fix(scope): ...`, `docs: ...`. +The main branch uses squash merges, so the PR title becomes the final commit message. + +## Changelog Entries + +Changelogen reads Conventional Commits directly, so please keep commit messages descriptive. Any user-facing change (features, fixes, deprecations, breaking updates) should have a clear `feat`, `fix`, or similar commit. Non-user-facing changes can use `chore`, `test`, etc. For PRs that squash multiple commits, summarize the user impact in the PR description so release managers can double-check the changelog entry. + +## Pull Requests + +Ensure the following before requesting review: +CI passes (test/typecheck/build/format) and the PR title follows Conventional Commits. + +## Release Workflow + +This repository now uses [changelogen](https://github.com/unjs/changelogen) to infer the next semantic version from Conventional Commits, update `CHANGELOG.md`, and create the release commit plus tag. The workflow is intentionally linear so that a single maintainer can ship safely end to end. + +1. Ensure `main` is up to date and clean. Run `pnpm changelog --no-output` if you want to preview the generated notes without touching the tree. +2. Execute `pnpm release`. This script runs `pnpm test`, `pnpm build`, and `changelogen --release` in sequence. The command bumps the version in `package.json`, rewrites `CHANGELOG.md`, and creates a `chore(release): vX.Y.Z` commit alongside the annotated `vX.Y.Z` tag. + - If you want to force a bump level or a specific version, run changelogen directly (recommended): `pnpm exec changelogen --release --minor` or `pnpm exec changelogen --release -r 0.4.0`. +3. Push the commit and tag together: `git push origin main --follow-tags`. If you need to stage multiple release commits, push in chronological order so tags stay in sync. +4. Tag pushes trigger `.github/workflows/publish.yml` automatically. The job runs on the `release` environment, installs dependencies, executes tests/type checks/build, publishes to npm via OIDC trusted publishing, and then calls `pnpm exec changelogen gh release vX.Y.Z --token $GITHUB_TOKEN` to sync the GitHub Release body with the freshly updated `CHANGELOG.md`. + +If the publish workflow fails, fix the root cause and re-run the job from the GitHub Actions UI. Avoid creating a new tag unless you intend to cut a new release. If you must roll back, delete the tag locally and remotely, revert the release commit, and start over from step 1. diff --git a/README.md b/README.md index b6722eb..ae6ad1a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ - [useDeepSignal](#usedeepsignal) - [useMolcule](#usemolcule) - [Testing](#testing) +- [Handling Scope Cleanup Errors](#handling-scope-cleanup-errors) - [Development](#development) - [License](#license) @@ -68,7 +69,7 @@ const CounterMolecule = molecule((props: { initialCount: number }) => { }); export function Counter(props: { initialCount: number }) { - const counter = useMolcule(CounterMolcule, props); + const counter = useMolcule(CounterMolecule, props); const value = useSignal(counter.count); return ( @@ -160,6 +161,32 @@ it("increments and displays the updated count", () => { }); ``` +## Handling Scope Cleanup Errors + +For global error handling configuration, see [@sigrea/core - Handling Scope Cleanup Errors](https://github.com/sigrea/core#handling-scope-cleanup-errors). + +In React apps, configure the handler in your application entry point before rendering: + +```tsx +// index.tsx or main.tsx +import { setScopeCleanupErrorHandler } from "@sigrea/core"; +import { createRoot } from "react-dom/client"; +import { App } from "./App"; + +setScopeCleanupErrorHandler((error, context) => { + console.error(`Cleanup failed:`, error); + + // Forward to monitoring service + if (typeof Sentry !== "undefined") { + Sentry.captureException(error, { + tags: { scopeId: context.scopeId, phase: context.phase }, + }); + } +}); + +createRoot(document.getElementById("root")!).render(); +``` + ## Development This repo targets Node.js 20 or later. @@ -174,9 +201,14 @@ You can also run pnpm scripts directly: - `pnpm install` — install dependencies. - `pnpm test` — run the Vitest suite once (no watch). +- `pnpm typecheck` — run TypeScript type checking. +- `pnpm test:coverage` — collect coverage. - `pnpm build` — compile via unbuild to produce dual CJS/ESM bundles. +- `pnpm cicheck` — run CI checks locally. - `pnpm dev` — launch the playground counter demo. +See [CONTRIBUTING.md](./CONTRIBUTING.md) for workflow details. + ## License MIT — see [LICENSE](./LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..36fbff9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Security Policy + +Please report vulnerabilities privately via GitHub Security Advisories. + +- Submit a private advisory: https://github.com/sigrea/react/security/advisories/new + +Do not open public issues for security reports. We will review and respond as appropriate. diff --git a/mise.toml b/mise.toml index 8f77ea9..ef13bc1 100644 --- a/mise.toml +++ b/mise.toml @@ -20,6 +20,12 @@ run = [ description = "Preview changelog notes (no file changes)" run = "pnpm exec changelogen --no-output" +[tasks.release_patch] +description = "Cut release commit + tag (force patch)" +depends = ["ci"] +confirm = "Create release commit + tag (patch) on main?" +run = 'test "$(git rev-parse --abbrev-ref HEAD)" = "main" && pnpm exec changelogen --clean --release --patch' + [tasks.release_minor] description = "Cut release commit + tag (force minor)" depends = ["ci"] diff --git a/package.json b/package.json index aaf1e28..4470c9c 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "test:coverage": "vitest --coverage", "typecheck": "tsc -p tsconfig.json --noEmit", "format": "biome check .", - "format:fix": "biome check --write ." + "format:fix": "biome check --write .", + "cicheck": "pnpm test && pnpm typecheck && pnpm format:fix" }, "peerDependencies": { "@sigrea/core": "^0.4.0",