Skip to content

Contributing ​

Thank you for considering contributing to @signkit/core! This guide covers development setup, testing, and PR expectations.

Getting Started ​

Prerequisites ​

  • Node.js 20+
  • npm (the repo uses npm workspaces)
  • Git

Development Setup ​

bash
# Clone the repository
git clone https://github.com/sign-kit/core.git
cd core

# Install dependencies
npm install

# Start the demo dev server
npm run dev:demo

# Start the docs site locally
npm run dev:docs

# Run unit tests (Vitest)
npm test

# Run Playwright e2e tests against the demo
npm run test:e2e

# Run linting
npm run lint

# Build the library
npm run build

Project Structure ​

packages/
  pdf-sign-kit/          # Publishable library (@signkit/core)
    src/
      components/        # Vue 3 components
      composables/       # Vue 3 composables
      utils/             # Utilities (signing, templates, integrity)
      styles/            # CSS tokens and base styles
      web-components/    # Custom element wrappers
      types.ts           # TypeScript interfaces
    test/                # Vitest unit & integration tests
    package.json

  demo/                  # Interactive demo app
    src/
      pages/             # Builder, Signer, Integrity, WebComponents pages
      App.vue
    package.json

  docs/                  # VitePress documentation site
    *.md                 # Markdown pages (getting-started, api/, etc.)
    package.json

tests/
  e2e/                   # Playwright browser tests (run against the demo)
    builder-signer.spec.ts
    demo-routes.spec.ts
    integrity.spec.ts
    webcomponent-events.spec.ts

Code Standards ​

TypeScript ​

  • All public APIs must be strongly typed
  • No any types (except where absolutely necessary, then comment why)
  • Use interfaces for data structures, not type aliases (for better IDE support)
typescript
// Good
interface Field {
  id: string
  type: FieldType
}

// Avoid
type Field = {
  id: string
  type: FieldType
}

Vue Components ​

  • Use Composition API with <script setup>
  • Provide explicit TypeScript types for props and emits
vue
<script setup lang="ts">
interface Props {
  pdf: string | File | ArrayBuffer
  modelValue: Template
  dateLocale?: string
}

const props = withDefaults(defineProps<Props>(), {
  dateLocale: 'en-US',
})

const emit = defineEmits<{
  'update:modelValue': [Template]
}>()
</script>

Utilities ​

  • Prefer small, pure functions
  • Avoid side effects
  • Add JSDoc comments for public functions
typescript
/**
 * Compute SHA-256 hash of data
 * @param data - Bytes to hash
 * @returns Hex-encoded hash string
 */
export async function computeSha256(data: ArrayBuffer): Promise<string> {
  const hashBuffer = await crypto.subtle.digest('SHA-256', data)
  return Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('')
}

Styling ​

  • Use CSS custom properties for colors, spacing, fonts
  • Define tokens in src/styles/tokens.css
  • No hardcoded colors or spacing values in component styles
css
/* Good */
.field {
  background: var(--sk-field-accent);
  color: var(--sk-color-text-primary);
  border-radius: var(--sk-radius-sm);
}

/* Avoid */
.field {
  background: #f0f0f0;
  color: #333;
  border-radius: 4px;
}

Testing ​

There are two layers of tests.

Vitest unit tests ​

Live in packages/pdf-sign-kit/test/. Run them with:

bash
npm test

The three test files cover:

  • utils.test.ts — integrity utilities: canonicalizeTemplate, computePdfHash, computeValuesHash
  • template.test.ts — template helpers: ensurePdfRoot, migratePdfSourceFromLegacy
  • finalize.test.ts — the full finalize flow: loads sample.pdf from disk, calls useSignerManager, and asserts the returned manifest has the expected shape

When adding a utility or composable, add a test in packages/pdf-sign-kit/test/. Keep tests focused — one describe block per module is fine.

Playwright e2e tests ​

Live in tests/e2e/ at the repo root and run against the locally served demo. Playwright spins up a dev server automatically (see playwright.config.ts).

bash
# Build the web component bundle, then run all tests headlessly
npm run test:e2e

# Skip the WC build (faster on repeat runs)
npm run test:e2e:skip-build

# Open the Playwright interactive UI
npm run test:e2e:ui

The four spec files test:

  • builder-signer.spec.ts — Builder renders with the sample PDF; Signer finalizes and emits a valid manifest
  • demo-routes.spec.ts — all demo routes load without errors
  • integrity.spec.ts — the integrity-verification event fires with the correct shape after finalize
  • webcomponent-events.spec.ts — the <pdf-form-builder> and <pdf-form-signer> custom elements emit the right events

For new features that touch the demo UI or the web component event contract, add or update a spec in tests/e2e/.

Making Changes ​

  1. Fork the repo and create a branch with a descriptive name:

    bash
    git checkout -b fix/signature-scaling
    git checkout -b feat/date-field-validation
  2. Make your changes. If you're adding something new, include tests.

  3. Before opening a PR, make sure everything passes:

    bash
    npm test
    npm run lint
  4. Open a pull request with a clear description of what changed and why. If it fixes a bug, explain how to reproduce it. If it's a new feature, show how it's used. Link any related issues.

For larger changes or anything that touches the public API, open an issue first to discuss the approach — it avoids wasted effort if the direction needs adjustment.

Documentation ​

The API reference under packages/docs/api/ is auto-generated from TSDoc comments via typedoc — you don't need to write or edit those files by hand. The docs:gen script handles it.

What contributors should do:

  • Add TSDoc comments to any new public functions, composables, or component props. This is what gets picked up by typedoc.
  • If your change affects how the library is used (new prop, changed behavior, new utility), update the relevant guide in packages/docs/ — e.g. usage/vue-usage.md, getting-started.md, or the integrity docs.
  • For breaking changes, note what needs to migrate in the PR description. A migration guide can be added to the docs as part of the release.

Releases ​

Releases are handled by the maintainer and the release pipeline — contributors don't need to bump versions, update the changelog, or tag releases. Just make sure your PR is clearly described so changes are easy to categorize.

Code Review ​

What to Expect ​

  • Tests: All PRs must include tests
  • TypeScript: Must pass type-checking
  • Linting: ESLint + Prettier
  • Documentation: Public APIs need docs
  • Performance: Large features need performance discussion

What Reviewers Look For ​

  • ✅ Code clarity and simplicity
  • ✅ Test coverage
  • ✅ No unnecessary dependencies
  • ✅ Consistency with existing code
  • ✅ Performance impact
  • ✅ Backwards compatibility (unless breaking is intentional)

Commit Messages ​

Use clear, descriptive commit messages:

feat: add role-based field access control
fix: signature scaling respects bounding box
docs: add server integration guide
test: add integrity hash verification tests
refactor: simplify field coordinate system

Format: <type>: <description>

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • test: Tests
  • refactor: Code refactoring
  • chore: Build, deps, tooling

Resources ​

Questions? ​

Open an issue or start a discussion on GitHub. We're happy to help!


Thank you for contributing! ❤️

Released under the Apache License 2.0.