Generate warm, heartfelt goodbye messages for email templates
Project description
Joyous Departures
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
-
Rust Toolchain (1.91.1+)
# Install Rust via rustup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env
-
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)
-
Python (3.14+)
# Using uv (recommended) curl -LsSf https://astral.sh/uv/install.sh | sh uv python install 3.14
-
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
-
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
-
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
-
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)
-
Build and Test Python Bindings
cd bindings/python maturin develop # Build Python extension in development mode uv run pytest tests/test_e2e.py
-
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
-
Run All Tests
# From repository root ./scripts/test.sh -
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 examplesscripts/test-typescript.sh- Quick test of TypeScript/WASM bindingsscripts/build.sh- Build all packages (Rust workspace, WASM, Python)scripts/bench.sh- Run benchmarks for all componentsscripts/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!:orBREAKING CHANGE:- Triggers major version bump (0.1.0 → 1.0.0)
How it works:
- Make commits with conventional commit messages
- Push to
mainbranch - After CI passes, semantic-release automatically:
- Analyzes commits since last release
- Determines next version
- Updates
Cargo.toml,package.json, andpyproject.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
reposcope- 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:
-
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
-
Set up Trusted Publishing on npmjs.com:
- Go to your package: https://www.npmjs.com/package/@siviter-xyz/joyous-departures
- Navigate to Settings → Trusted Publishers
- Click Add Trusted Publisher
- Select GitHub Actions
- Configure:
- Repository:
siviter-xyz/joyous-departures - Workflow file:
.github/workflows/publish.yml(must match exactly, including.ymlextension) - Environment name: (leave empty unless using environments)
- Repository:
- Save the configuration
-
Verify the workflow is ready:
- The workflow already has
id-token: writepermissions for OIDC - npm will be updated to the latest version automatically
- Future publishes will use OIDC authentication automatically
- The workflow already has
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
ccnot found": Installbuild-essential(see Prerequisites #2) - "clang not found" (WASM builds): Install
clangviasudo apt-get install clang - "cargo: command not found": Run
source ~/.cargo/envor add~/.cargo/binto PATH - Python import errors: Ensure
maturin developwas run inbindings/python/venv - WASM build fails: Ensure
wasm-packis installed andclangis available - maturin install fails via cargo: Use
uv venvanduv pip install maturininstead
Documentation
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file joyous_departures-1.7.0-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: joyous_departures-1.7.0-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 561.3 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15ece425ee0b1b8f3edf605146ca9359f507f08b8825329dbde03b38e8c2e060
|
|
| MD5 |
3de02f34a99b321712cffc8d90f71e16
|
|
| BLAKE2b-256 |
5b659c27e019bde35c2d6448fd1184e4a0944ca82ecdf370d08917477c7f830a
|