Skip to content

Latest commit

 

History

History
224 lines (156 loc) · 11.7 KB

CONTRIBUTING.md

File metadata and controls

224 lines (156 loc) · 11.7 KB

Contributing to @addon-core/inject-script

Thank you for helping improve @addon-core/inject-script.

This package provides one typed script-injection contract across Manifest V2 and Manifest V3. Contributions should preserve that cross-manifest boundary, keep unsupported capabilities explicit, and include verification for every affected adapter.

By participating, you agree to follow our Code of Conduct. Report vulnerabilities through the private process described in SECURITY.md, not through a public issue.

Development workflow

The repository uses a simplified GitFlow model:

  • main contains released code.
  • develop is the integration branch and the normal pull-request target.
  • feature/<short-name> branches start from develop.
  • Releases are prepared by merging develop into main.
  • After a successful release, the workflow syncs main back into develop.

Create a branch from the latest develop:

git switch develop
git pull --ff-only
git switch -c feature/<short-name>

Local setup

Node.js 20 is the default CI environment. Pull requests into main and the release gate also exercise Node.js 18, 20, and 22.

git clone git@github.com:addon-stack/inject-script.git
cd inject-script
npm ci

Useful commands:

Command Purpose
npm run dev Build continuously with tsup
npm run build Create ESM, CJS, and declaration outputs
npm run format Format supported files with Biome
npm run format:check Check formatting without writing
npm run lint Run Biome formatting and lint checks
npm run lint:fix Apply safe Biome fixes
npm run lint:fix:unsafe Apply safe and unsafe Biome fixes
npm run typecheck Type-check package sources
npm run test:types Type-check public API contract fixtures
npm run test Build and run the Jest suite
npm run test:ci Build, run Jest with coverage, and check dependency-release integration
npm run test:tooling Verify Renovate, commitlint, and changelog integration
npm run release Perform a real maintainer release through release-it

npm run release is not a dry run. Do not execute it unless you are intentionally publishing a release and have the required maintainer access.

Contribution guidelines

Keep changes focused and preserve the package's public design:

  • Every operation has one explicit target.
  • Target selectors remain mutually exclusive.
  • Unsupported targets and options fail explicitly; they are never removed silently.
  • run() uses best-effort target isolation and returns package-owned success/failure outcomes instead of raw browser results.
  • Explicit target calls start synchronously before the first result is awaited so user activation is preserved.
  • Callback arguments and results remain strictly JSON-compatible.
  • MV2 injected code must stay self-contained because imports and caller closures do not cross the injection boundary.
  • Runtime code must not introduce eval or new Function.
  • Frame discovery, RPC fan-out, concurrency queues, and application-specific aggregation remain outside this package.

When changing public behavior, update the implementation, types, tests, and README together.

Tests

The test suite covers the following contracts:

  • tests/types.test.ts verifies compile-time API behavior.
  • tests/inject-script.test.cjs verifies MV2/MV3 runtime behavior against the built package.
  • tests/release-it.test.cjs verifies release versioning policy.
  • tests/dependency-release.test.mjs verifies the real parser, commitlint CLI, and generated dependency release notes.

For adapter changes, cover the affected combinations where relevant:

  • Manifest V2 and Manifest V3;
  • callback-based global.chrome and Promise-based global.browser;
  • top frame, allFrames, explicit frameIds, and documentIds;
  • success and failure outcomes, including execution, delivery, timeout, and target-gone errors;
  • input ordering and synchronous initiation of explicit target batches;
  • valid JSON data and runtime-only invalid values;
  • preparation errors, native delivery failures, and timeouts.

MV2 payload tests execute the generated code in a separate process. Keep this path covered when changing serialized injected logic.

Quality gates

Before opening a pull request, run:

npm run lint
npm run typecheck
npm run test:ci

test:ci already runs type-contract tests and a production build before Jest.

Local hooks provide additional protection:

  • pre-commit runs lint-staged, which formats and lints supported staged source/config files.
  • commit-msg validates Conventional Commits with commitlint.
  • pre-push runs typecheck and the full test:ci command.

GitHub Actions repeats lint, typecheck, tests, coverage, and production build checks. Pull requests into main and release runs use the full operating-system and Node.js matrix. The aggregate CI passed check also requires strict Renovate configuration validation; failed, cancelled, or skipped prerequisites fail this check.

Commit messages

All commits must follow Conventional Commits:

<type>(optional scope): <short summary>

[optional body]
[optional footer]

Common examples:

feat(target): add document targeting
fix(mv2): preserve partial timeout results
deps: update dependencies
ci: update workflow actions
refactor(results): centralize native normalization
test(types): cover interface arguments
docs: simplify the quick start

Use ! or a BREAKING CHANGE: footer for an incompatible public change:

feat!: replace the legacy target options

Commit messages are enforced by .husky/commit-msg and .commitlintrc.json.

Versioning policy

Release versions are derived from commit history by release-it and @release-it/conventional-changelog:

  • A breaking change increments major at 1.x and newer.
  • A breaking change increments minor while the package is on 0.x.
  • feat and revert increment minor.
  • fix, deps, perf, and refactor increment patch.
  • docs, test, build, chore, ci, and style do not trigger a release by themselves.
  • When several changes are present, the highest applicable increment wins.

Do not edit released changelog entries manually. CHANGELOG.md is generated from Conventional Commits during release.

Automated dependency updates

The Update Dependencies workflow runs every Sunday at 02:15 America/Los_Angeles and can also be started from Actions → Update Dependencies → Run workflow. The time follows Los Angeles daylight saving rules.

Renovate reads renovate.json from main and updates only @addon-core/browser and @types/chrome, together with their required lockfile changes. Stable updates of any size are grouped in one deps/update-dependencies branch and one PR into main, including Chrome-types-only updates. Other direct dependencies and standalone lockfile maintenance are disabled.

On each run, Renovate refreshes its branch from the current main when needed. An open bot-managed PR is updated in place. After merging, a future update can recreate the same branch name. No available update means no empty PR. Manually committing to an open bot branch pauses automatic updates to protect those commits.

The bot creates deps: update dependencies commits. Ordinary dependency-only changes trigger a patch release and appear under 📦 Dependencies in the changelog and GitHub release notes. Keep the deps: ... title when squashing. Breaking markers and other commits still follow the normal release policy.

The App token triggers the normal PR checks: lint, source and public API type checks, build, tests, and strict Renovate configuration validation. Merging remains manual. Failed checks leave the PR open and do not publish a release. After merge, the existing Release workflow repeats the full checks, publishes the package, and syncs main back into develop.

Keep conventional-commits-parser 6.x as an explicit development dependency. The release tooling needs parser 6.x through optional peers, while commitlint needs parser 5.x. Explicitly declaring parser 6.x prevents npm lockfile-only regeneration from dropping the release parser. After changing it, regenerate the lockfile in a clean directory and verify npm ci and the release tooling tests.

Connect the shared GitHub App

Reuse the existing organization App addon-stack-dependency-updates; each package keeps its own workflow and dependency rules.

  1. In the addon-stack organization settings, open GitHub Apps → Configure for the existing installation and add inject-script under Only select repositories. Keep existing repositories selected. The existing App permissions are sufficient; no new App or key is needed.
  2. Under Secrets and variables → Actions, add inject-script to the selected repositories for both the organization variable RENOVATE_APP_CLIENT_ID and the organization secret RENOVATE_APP_PRIVATE_KEY. The workflow creates a short-lived token scoped to this repository only. Renovate does not need an npm publishing token.
  3. Merge the setup from develop into main. Both scheduled runs and the manual workflow entry need the workflow file on the default branch.
  4. Run Update Dependencies manually and inspect the first PR. Configure the PR check CI passed as required for main and require an up-to-date branch. Do not give the dependency App a branch-protection bypass.
  5. Account for release automation before enforcing branch rules: release-it pushes version/changelog commits to main, and the sync step writes to develop. Rules requiring PRs for all writes need a suitable exception for the release writer; the dependency App is not the release writer.

For another package, repeat the installation and organization-variable/secret access steps, then add its workflow, dependency allowlist, release policy, tests, and documentation. GitHub supports changing the repositories available to an installed App and sharing organization secrets with selected repositories.

Pull requests

Open regular pull requests against develop and include:

  • a concise explanation of the problem and the chosen solution;
  • tests for changed behavior;
  • documentation for public API or contract changes;
  • migration notes for breaking changes;
  • links to related issues when available.

Pull-request checklist:

  • The change is focused and contains no unrelated edits.
  • MV2 and MV3 implications have been considered.
  • npm run lint passes.
  • npm run typecheck passes.
  • npm run test:ci passes.
  • Public documentation is updated when necessary.
  • Commit messages follow Conventional Commits.

Maintainers create release pull requests from develop into main.

Releases

The release workflow runs on pushes to main and through manual dispatch:

  1. Run the full CI matrix.
  2. Calculate the next version from Conventional Commits unless an exact version was provided.
  3. Update package.json and CHANGELOG.md.
  4. Create the release commit and Git tag.
  5. Create a GitHub Release.
  6. Publish the public npm package with provenance through trusted publishing.
  7. Sync main back into develop.

The workflow accepts optional prerelease and npm dist-tag inputs. It uses GitHub OIDC permissions for npm provenance and does not depend on a documented contributor NPM_TOKEN flow.

Publishing is a maintainer operation. Contributors only need to prepare a complete, verified pull request into develop.

License

By contributing, you agree that your contributions are licensed under the project's MIT License.