Thank you for your interest in contributing to Seal! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Workflow
- Coding Standards
- Testing
- Pull Request Process
- Security
- Be respectful and inclusive
- Accept constructive criticism gracefully
- Focus on what's best for the community
- Show empathy towards other contributors
- Harassment, trolling, or discriminatory language
- Publishing others' private information
- Personal attacks or political arguments
- Spam or off-topic discussions
- Node.js 20.x or higher
- npm or yarn package manager
- Git
- A code editor (VS Code recommended)
# Fork the repository on GitHub
# Clone your fork
git clone https://github.com/YOUR-USERNAME/seal.git
cd seal
# Add upstream remote
git remote add upstream https://github.com/ORIGINAL-OWNER/seal.git
# Install dependencies
npm install
# Start development server
npm run devseal/
├── src/
│ ├── lib/ # Core libraries
│ │ ├── crypto.ts # Encryption functions
│ │ ├── tlock.ts # Time-lock implementation
│ │ ├── storage.ts # Browser storage
│ │ └── vef.ts # Vault Export Format
│ ├── components-vanilla/ # UI components
│ ├── styles/ # CSS modules
│ └── main.ts # Entry point
├── public/ # Static assets
├── scripts/ # Build/deployment scripts
└── tests/ # Test files (when added)
main— Production-ready codefeature/*— New featuresfix/*— Bug fixesdocs/*— Documentation changesrefactor/*— Code improvements
# Update your main branch
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/your-feature-name-
Write Code
- Follow coding standards (see below)
- Keep commits small and focused
- Write clear commit messages
-
Test Locally
npm run dev # Start dev server npm run build # Test production build npm test # Run tests (when added)
-
Commit Changes
git add . git commit -m "feat: add awesome feature"
Follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
feat— New featurefix— Bug fixdocs— Documentation onlystyle— Code style (formatting, semicolons)refactor— Code change that neither fixes bug nor adds featuretest— Adding or updating testschore— Build process, tooling, dependencies
Examples:
feat: add burn-after-reading option
fix: date picker not visible on mobile
docs: update README with deployment instructions
refactor: simplify base64 encoding logic
test: add unit tests for crypto functions
chore: update dependencies to latest- Strict mode enabled — All code must type-check
- No
anytypes — Useunknownor proper types - Explicit return types — For public functions
- No console.log — Use proper logging (or remove before commit)
// ✅ Good
export async function encryptVault(
content: string,
unlockTime: number,
): Promise<VaultRef> {
const key = await generateKey();
const encrypted = await encrypt(content, key);
return { encrypted, unlockTime };
}
// ❌ Bad
export async function encryptVault(content, unlockTime) {
let key = await generateKey()
let encrypted = await encrypt(content, key)
return { encrypted: encrypted, unlockTime: unlockTime }
}- One component per file
- Group related functionality
- Export public API at end
- Import order: external → internal → types
// External dependencies first
import { timelockEncrypt } from 'tlock-js';
import { get, set } from 'idb-keyval';
// Internal dependencies
import { generateKey } from './crypto';
import { toBase64 } from './encoding';
// Types last
import type { VaultRef } from './storage';- Use design tokens — Reference
tokens.cssvariables - Mobile-first — Desktop styles in media queries
- BEM-like naming — Descriptive class names
- No inline styles — Except dynamic values
/* ✅ Good */
.vaultCard {
padding: var(--space-4);
background: var(--color-surface);
border: 1px solid var(--color-border);
}
@media (min-width: 768px) {
.vaultCard {
padding: var(--space-6);
}
}
/* ❌ Bad */
.card {
padding: 16px;
background: #1a1a1a;
border: 1px solid #333;
}- JSDoc for public APIs
- Inline comments for complex logic
- README for user-facing features
- Code is self-documenting — Clear names over comments
/**
* Creates a time-locked vault that cannot be opened until the specified time.
*
* @param content - The plaintext content to encrypt
* @param unlockTime - Unix timestamp (ms) when vault becomes unlockable
* @param options - Optional vault configuration
* @returns Promise resolving to vault reference
* @throws {Error} If unlock time is in the past
*
* @example
* ```typescript
* const vault = await createVault(
* "Secret message",
* Date.now() + 86400000, // 24 hours
* { destroyAfterRead: true }
* );
* ```
*/
export async function createVault(
content: string,
unlockTime: number,
options?: VaultOptions,
): Promise<VaultRef> {
// Implementation
}npm test # Run all tests
npm test -- --watch # Watch mode
npm test -- crypto # Run specific test file
npm run test:coverage # Generate coverage report- Unit tests — Pure functions, business logic
- Integration tests — Component interactions
- E2E tests — Critical user flows (future)
import { describe, it, expect } from 'vitest';
import { toBase64, fromBase64 } from '../src/lib/encoding';
describe('encoding', () => {
describe('toBase64', () => {
it('should encode Uint8Array to base64', () => {
const data = new Uint8Array([72, 101, 108, 108, 111]);
const result = toBase64(data);
expect(result).toBe('SGVsbG8');
});
it('should produce URL-safe base64', () => {
const data = new Uint8Array([255, 255, 255]);
const result = toBase64(data);
expect(result).not.toContain('+');
expect(result).not.toContain('/');
});
});
describe('fromBase64', () => {
it('should decode base64 to Uint8Array', () => {
const result = fromBase64('SGVsbG8');
expect(result).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
});
it('should handle URL-safe base64', () => {
const encoded = toBase64(new Uint8Array([255, 255, 255]));
const decoded = fromBase64(encoded);
expect(decoded).toEqual(new Uint8Array([255, 255, 255]));
});
});
});- Cryptographic functions — 100%
- Business logic — 90%+
- UI components — 70%+
- Overall — 80%+
- Code builds without errors (
npm run build) - Tests pass (
npm test) - Code follows style guidelines
- Commits follow conventional format
- Branch is up to date with main
- Self-review completed
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix (non-breaking change fixing an issue)
- [ ] New feature (non-breaking change adding functionality)
- [ ] Breaking change (fix or feature causing existing functionality to break)
- [ ] Documentation update
## Testing
How has this been tested?
## Security Impact
Does this change affect cryptography, authentication, or data handling?
## Checklist
- [ ] My code follows the project's style guidelines
- [ ] I have performed a self-review
- [ ] I have commented my code where needed
- [ ] I have updated documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix/feature works
- [ ] New and existing tests pass locally-
Automated Checks
- Build verification
- Test suite
- Lint checks
- Type checking
-
Manual Review
- Code quality
- Security implications
- Performance impact
- Documentation
-
Approval
- At least 1 maintainer approval required
- All CI checks must pass
- Conflicts must be resolved
-
Merge
- Squash and merge (for features)
- Rebase and merge (for fixes)
- Maintainer will merge when ready
- Delete your feature branch
- Pull latest main
- Celebrate! 🎉
Do not include security vulnerabilities in public PRs.
If you discover a security issue:
- Do NOT open a public issue
- Follow the Security Policy
- Report privately via GitHub Security Advisories
Changes to cryptographic code require extra scrutiny:
- Breaking changes — May require VEF version bump
- Test vectors — Provide known-good inputs/outputs
- Security review — Tag maintainers for review
- Documentation — Explain cryptographic decisions
The Vault Export Format is versioned. Changes require:
- Version bump in
vef.ts - Migration guide in
CHANGELOG.md - Backward compatibility tests
- Update README examples
For user-facing changes:
- Test on mobile and desktop
- Verify accessibility (keyboard navigation, screen readers)
- Include screenshots in PR description
- Consider i18n implications (future)
Contributors are recognized in:
- Release notes
- README acknowledgments
- Git commit history
Thank you for contributing to Seal! 🚀