Skip to main content

Generate warm, heartfelt goodbye messages for email templates

Project description

Joyous Departures

Joyous Departures

npm version PyPI version CI License: MIT Rust

Generate warm, heartfelt sign-off messages for email templates and other communication contexts.

Overview

A high-performance library that generates random, warm sign-off messages from a pre-curated corpus. The core generation logic is implemented in Rust for speed, with language bindings provided for TypeScript (npm package) and Python (PyPI package).

Over-engineered? Most definitely.

This project is an exploration of spec-first AI-assisted design and simultaneously targetting multiple consumer languages from a high-performance Rust core. It is also an ode to a cherished partner and the aspects they inspire deeply within myself and in many others ❤️

Most importantly, as ever, because it was fun!

Features

  • 🚀 Fast: Message generation in <10ms
  • 🌍 International: Support for multiple languages (with translator callback)
  • 🎨 Customizable: Template variables ({name}, {location}, {date}, {time})
  • 😊 Emoji Support: Emojis included by default, with option to strip
  • 🌐 Browser Ready: TypeScript bindings use WASM for browser support
  • 📦 Easy to Use: Simple API, works with pnpm and uv

Template Variables

Messages can include template variables that are replaced with custom values or defaults:

Variable Default Value Format Description
{name} "Good Soul" Any string (max 50 chars) Recipient's name
{location} "The World" Any string Location context
{date} Current date YYYY-MM-DD Current date in specified timezone
{time} Current time HH:MM Current time in specified timezone

Note: Not all messages include template variables. Some messages are simple phrases without any variables.

Installation

TypeScript/JavaScript

pnpm add @siviter-xyz/joyous-departures
# or
npm install @siviter-xyz/joyous-departures

Python

uv pip install joyous-departures

Quick Start

See quickstart guide for detailed examples.

TypeScript

import { generateGoodbye } from '@siviter-xyz/joyous-departures';

const message = await generateGoodbye({
  templateArgs: { name: 'Alice' }
});
console.log(message); // "Wishing you a joyous day, Alice ❤️"

Python

import asyncio
from joyous_departures import generate_goodbye

async def main():
    message = await generate_goodbye(template_args={"name": "Alice"})
    print(message)  # "Wishing you a joyous day, Alice ❤️"

asyncio.run(main())

Local Development Setup

Prerequisites

  1. Rust Toolchain (1.91.1+)

    # Install Rust via rustup
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    source ~/.cargo/env
    
  2. Build Tools (for compiling Rust dependencies)

    # Debian/Ubuntu/WSL
    sudo apt-get update
    sudo apt-get install build-essential clang
    
    # This provides: gcc, g++, make, clang, and other essential build tools
    # clang is needed for WASM builds (lz4 dependency)
    
  3. Python (3.14+)

    # Using uv (recommended)
    curl -LsSf https://astral.sh/uv/install.sh | sh
    uv python install 3.14
    
  4. Node.js (18+) and pnpm

    # Install Node.js via nvm (recommended)
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
    nvm install 18
    nvm use 18
    
    # Install pnpm
    npm install -g pnpm
    
  5. Build Tools for Bindings

    # Install wasm-pack (for TypeScript/WASM bindings)
    source ~/.cargo/env
    cargo install wasm-pack
    # Verify: wasm-pack --version
    
    # Install maturin (for Python bindings)
    # Option 1: Via pip (recommended, faster, avoids cargo dependency conflicts)
    pip install maturin
    # or with uv:
    uv pip install maturin --system
    
    # Option 2: Via cargo (requires build-essential, may have dependency conflicts)
    source ~/.cargo/env
    cargo install maturin
    # Verify: maturin --version
    

Development Workflow

  1. Clone and Setup

    git clone <repository-url>
    cd joyous-departures
    source ~/.cargo/env  # If Rust is installed via rustup
    
    # Install pre-commit hooks (recommended)
    ./scripts/setup-git-hooks.sh
    
  2. Run Rust Core Tests

    source ~/.cargo/env  # Ensure cargo is in PATH
    cd joy-generator
    cargo test           # ✅ All 21 tests should pass
    cargo bench          # Run benchmarks (shows ~615ns generation time)
    
  3. Build and Test Python Bindings

    cd bindings/python
    maturin develop  # Build Python extension in development mode
    uv run pytest tests/test_e2e.py
    
  4. Build and Test TypeScript Bindings

    cd bindings/typescript
    source ~/.cargo/env
    wasm-pack build --target web --out-dir pkg
    pnpm install
    pnpm test
    # Note: Requires clang (see Prerequisites #2) for lz4 dependency
    
  5. Run All Tests

    # From repository root
    ./scripts/test.sh
    
  6. Quick Test Individual Components

    # Test Python bindings
    ./scripts/test-python.sh
    
    # Test TypeScript/WASM bindings
    ./scripts/test-typescript.sh
    

Available Scripts

All scripts are located in the scripts/ directory:

  • scripts/test.sh - Run all test suites (Rust, Python, TypeScript)
  • scripts/lint.sh - Run linting checks (format + clippy, same as CI)
  • scripts/setup-git-hooks.sh - Install pre-commit hooks (runs linting automatically)
  • scripts/test-python.sh - Quick test of Python bindings with examples
  • scripts/test-typescript.sh - Quick test of TypeScript/WASM bindings
  • scripts/build.sh - Build all packages (Rust workspace, WASM, Python)
  • scripts/bench.sh - Run benchmarks for all components
  • scripts/get-version.sh - Extract version from git tag (used by build processes)
  • scripts/update-versions.sh - Update version in all package files (used by semantic-release)
  • scripts/publish.sh - Publish packages to npm and PyPI (manual publishing)

Required Stack

Prerequisites:

  • Rust 1.91.1+ (cargo, rustc)
  • build-essential (gcc 14.2.0+) + clang
  • wasm-pack 0.13.1+
  • uv 0.9.6+
  • pnpm 10.16.1+
  • Node.js 18+
  • Python 3.13+ (via uv)
  • maturin 1.10.2+ (via uv venv)

Performance Benchmarks:

  • Generation Time: ~615ns per message (0.000615ms)
    • Target: <10ms
    • Actual: 16,260x faster than target
  • Corpus Loading: ~10ns (cached after first load)
  • Throughput: 1000+ concurrent calls/second ✅
  • Memory: <10MB total footprint ✅

Run benchmarks with: cargo bench --manifest-path joy-generator/Cargo.toml

To Verify Your Setup:

# 1. Verify Rust core
source ~/.cargo/env
cd joy-generator
cargo test      # Expected: "21 passed; 0 failed"
cargo bench     # Expected: ~615ns for generate_goodbye

# 2. Verify Python bindings
cd bindings/python
uv venv --python 3.13 && source .venv/bin/activate
uv pip install maturin pytest pytest-asyncio
maturin develop
pytest tests/test_e2e.py  # Expected: "8 passed"

# 3. Verify TypeScript/WASM (requires clang)
cd bindings/typescript
source ~/.cargo/env
wasm-pack build --target web --out-dir pkg
pnpm install && pnpm test  # Expected: "10 passed"

# Or use the convenience scripts:
./scripts/test.sh   # Run all tests
./scripts/lint.sh   # Run linting checks (format + clippy, same as CI)

Pre-Commit Setup

Recommended: Install git hooks for automatic linting

The easiest way to ensure code quality is to install the pre-commit hook, which automatically runs linting checks before each commit:

# One-time setup (run this after cloning the repo)
./scripts/setup-git-hooks.sh

How it works: Git hooks in .git/hooks/ are not tracked by git (they're local to each repository clone). The hooks are stored in .githooks/ (which IS tracked), and setup-git-hooks.sh copies them to .git/hooks/ for each developer.

After setup, the pre-commit hook will automatically run ./scripts/lint.sh before each commit. If linting fails, the commit will be blocked.

Manual alternative:

If you prefer to run checks manually:

# 1. Run linting (format + clippy) - same as CI
./scripts/lint.sh

# 2. Run all tests
./scripts/test.sh

Why this matters: CI runs cargo clippy --all-targets --all-features -- -D warnings, which treats warnings as errors. The pre-commit hook ensures you catch the same issues before pushing.

Version Management

Automated Versioning with Semantic-Release:

The project uses semantic-release to automatically manage versions based on conventional commits:

  • feat: - Triggers minor version bump (0.1.0 → 0.2.0)
  • fix: - Triggers patch version bump (0.1.0 → 0.1.1)
  • feat!: or BREAKING CHANGE: - Triggers major version bump (0.1.0 → 1.0.0)

How it works:

  1. Make commits with conventional commit messages
  2. Push to main branch
  3. After CI passes, semantic-release automatically:
    • Analyzes commits since last release
    • Determines next version
    • Updates Cargo.toml, package.json, and pyproject.toml
    • Creates git tag (e.g., v0.1.1)
    • Generates/updates CHANGELOG.md
    • Triggers publish workflow

Version Scripts:

  • scripts/get-version.sh - Extracts version from git tags (used by build processes)
  • scripts/update-versions.sh - Updates version in all package files (used by semantic-release)

Publishing Prerequisites:

Before publishing, you need to add GitHub secrets:

  • PYPI_API_TOKEN - PyPI API token (create at https://pypi.org/manage/account/token/)
  • GH_PAT (required) - GitHub Personal Access Token with repo scope
    • Required for semantic-release to push tags that trigger the publish workflow
    • Tags pushed by GITHUB_TOKEN don't trigger workflows in GitHub Actions
    • Create at https://github.com/settings/tokens
    • Add as a repository secret named GH_PAT

Initial npm Package Setup (One-time):

npm classic tokens are deprecated. You must publish the first version manually, then set up Trusted Publishing:

  1. Publish the first version manually:

    cd bindings/typescript
    npm login  # This will prompt for your npm username, password, and 2FA code
    npm publish --access public
    
  2. Set up Trusted Publishing on npmjs.com:

    • Go to your package: https://www.npmjs.com/package/@siviter-xyz/joyous-departures
    • Navigate to SettingsTrusted Publishers
    • Click Add Trusted Publisher
    • Select GitHub Actions
    • Configure:
      • Repository: siviter-xyz/joyous-departures
      • Workflow file: .github/workflows/publish.yml (must match exactly, including .yml extension)
      • Environment name: (leave empty unless using environments)
    • Save the configuration
  3. Verify the workflow is ready:

    • The workflow already has id-token: write permissions for OIDC
    • npm will be updated to the latest version automatically
    • Future publishes will use OIDC authentication automatically

Note: Classic npm tokens are deprecated and will be revoked on December 9, 2025. Trusted Publishing is the only supported method for automated publishing.

Manual Publishing (if needed):

If you need to publish manually without semantic-release:

# 1. Create a version tag
git tag v0.1.0

# 2. Update version in all files
./scripts/update-versions.sh 0.1.0

# 3. Build packages
./scripts/build.sh

# 4. Publish
cd bindings/typescript && pnpm publish --access public
cd ../python && maturin publish

Troubleshooting

  • "linker cc not found": Install build-essential (see Prerequisites #2)
  • "clang not found" (WASM builds): Install clang via sudo apt-get install clang
  • "cargo: command not found": Run source ~/.cargo/env or add ~/.cargo/bin to PATH
  • Python import errors: Ensure maturin develop was run in bindings/python/ venv
  • WASM build fails: Ensure wasm-pack is installed and clang is available
  • maturin install fails via cargo: Use uv venv and uv pip install maturin instead

Documentation

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

joyous_departures-1.6.4-cp313-cp313-manylinux_2_34_x86_64.whl (563.1 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ x86-64

File details

Details for the file joyous_departures-1.6.4-cp313-cp313-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for joyous_departures-1.6.4-cp313-cp313-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 11ebe928272019889de2a03ce8613730f4582cd41e0d778ea26408e0d6e16427
MD5 5b8b98d67d4713ddcdab5d343101b7b5
BLAKE2b-256 03c92645b8edc541f78826d74441f89017889251baff1a365b9a898fea0a4501

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page