|
| 1 | +Thank you for your interest in contributing to `privy-rs`! We're excited to see your contributions. This guide will help you get set up and follow the development practices of this project. |
| 2 | + |
| 3 | +*** |
| 4 | + |
| 5 | +## Development Setup |
| 6 | + |
| 7 | +This project uses [mise](https://mise.jdx.dev/) to manage the development environment, including the Rust toolchain version and environment variables defined in the `rust-toolchain.toml` file. |
| 8 | + |
| 9 | +### Initial Setup |
| 10 | + |
| 11 | +1. **Clone the repository:** |
| 12 | + ```bash |
| 13 | + git clone https://github.com/your-username/privy-rs.git |
| 14 | + cd privy-rs |
| 15 | + ``` |
| 16 | + |
| 17 | +2. **Install mise:** Follow the instructions on the [mise website](https://mise.jdx.dev/getting-started.html). |
| 18 | + |
| 19 | +3. **Install dependencies:** Run `mise install` in the project root to install the required Rust toolchain and other tools. |
| 20 | + |
| 21 | +4. **Activate environment:** Run `mise trust` in the project root to approve the configuration. `mise` will automatically pick up the Rust version from the `rust-toolchain.toml` file. |
| 22 | + |
| 23 | +5. **Build the project:** Build the project to ensure everything is set up correctly. This will also trigger the initial code generation step. |
| 24 | + ```bash |
| 25 | + cargo build |
| 26 | + ``` |
| 27 | + |
| 28 | +The `.mise.toml` file contains placeholders for the required environment variables. You can set them there or in a `.env` file for `mise` to load. |
| 29 | + |
| 30 | +### Environment Variables |
| 31 | + |
| 32 | +Copy the example environment file and fill in your Privy credentials: |
| 33 | + |
| 34 | +```bash |
| 35 | +cp .env.example .env |
| 36 | +``` |
| 37 | + |
| 38 | +Then edit `.env` with your actual Privy credentials: |
| 39 | + |
| 40 | +```env |
| 41 | +PRIVY_APP_ID=your_app_id |
| 42 | +PRIVY_APP_SECRET=your_app_secret |
| 43 | +PRIVY_WALLET_ID=your_wallet_id |
| 44 | +``` |
| 45 | + |
| 46 | +See `.env.example` for all available environment variables including staging/testing configurations. |
| 47 | + |
| 48 | +### OpenAPI Spec Management |
| 49 | + |
| 50 | +This project uses Privy's OpenAPI specification to generate client code. To update the OpenAPI spec: |
| 51 | +
|
| 52 | +```bash |
| 53 | +mise run pull-openapi |
| 54 | +
|
| 55 | +# this automatically runs pull first |
| 56 | +mise run gen-openapi |
| 57 | +``` |
| 58 | +
|
| 59 | +This command: |
| 60 | +
|
| 61 | +1. Downloads the latest OpenAPI spec from `https://api.privy.io/v1/openapi.json` |
| 62 | +2. Applies local overlay from `openapi.overlay.json` to add operation IDs and other fixes |
| 63 | +3. Processes the spec to remove `privy-app-id` from operation parameters |
| 64 | +4. Replaces `anyOf` with `oneOf` for better code generation |
| 65 | +5. Saves the processed spec to `openapi.json` |
| 66 | +6. Generates the Rust client code |
| 67 | +
|
| 68 | +*** |
| 69 | +
|
| 70 | +## Testing |
| 71 | +
|
| 72 | +This project includes comprehensive test coverage across multiple levels: |
| 73 | +
|
| 74 | +### Test Categories |
| 75 | +
|
| 76 | +- **Module Tests (mod tests):** Unit tests located inside the source files they are testing (e.g., within `src/keys.rs`). They are meant to test specific, isolated functionality in a "white-box" manner. They should be fast and have no external dependencies. |
| 77 | +
|
| 78 | +- **Integration Tests (`/tests` directory):** "Black-box" tests located in the `tests/` directory. They test the public API of the crate as an external user would, ensuring different parts of the library work together correctly. |
| 79 | +
|
| 80 | + > Important: These tests make real API calls and require environment variables to be set (e.g., PRIVY_APP_ID, PRIVY_APP_SECRET). Create a `.env` file in the root of the project to manage these secrets. |
| 81 | +
|
| 82 | +- **Doctests:** Tests written directly inside the documentation comments (`///`) of a function or module. They serve as verifiable examples, ensuring that the documentation is always correct and up-to-date. They are automatically run with the main test suite. |
| 83 | +
|
| 84 | +- **Examples (`/examples` directory):** Runnable programs that demonstrate how to use the library. While not run by `cargo test`, they serve as end-to-end integration tests and document real-world usage patterns. You can run an example with: |
| 85 | +
|
| 86 | + ```bash |
| 87 | + # This also requires environment variables to be set |
| 88 | + cargo run --example get_wallets |
| 89 | + ``` |
| 90 | +
|
| 91 | +### Environment Setup for Testing |
| 92 | +
|
| 93 | +#### Staging Environment Variables |
| 94 | +
|
| 95 | +For end-to-end tests, configure these environment variables: |
| 96 | +
|
| 97 | +```bash |
| 98 | +# Required for all E2E tests |
| 99 | +export PRIVY_TEST_APP_ID="your_staging_app_id" |
| 100 | +export PRIVY_TEST_APP_SECRET="your_staging_app_secret" |
| 101 | +export PRIVY_TEST_URL="https://api.staging.privy.io" # Optional, defaults to production |
| 102 | +export PRIVY_TEST_JWT_PRIVATE_KEY="your_test_jwt_token" # JWT authentication tests |
| 103 | +``` |
| 104 | +
|
| 105 | +### Running Tests |
| 106 | +
|
| 107 | +To run all module tests, integration tests, and doctests, use: |
| 108 | +
|
| 109 | +```bash |
| 110 | +cargo test --all |
| 111 | +
|
| 112 | +# Run specific module tests |
| 113 | +cargo test keys |
| 114 | +cargo test client |
| 115 | +``` |
| 116 | +
|
| 117 | +*** |
| 118 | +
|
| 119 | +## Understanding the Codebase |
| 120 | +
|
| 121 | +A significant portion of the client code in this repository is auto-generated to ensure it stays in sync with the Privy OpenAPI specification. |
| 122 | +
|
| 123 | +### Progenitor |
| 124 | +
|
| 125 | +We use `cargo-progenitor` to generate the base client and subclients. This tool is a wrapper around the `progenitor` crate, which is responsible for generating the typed subclients that provide a convenient, resource-oriented interface. The resulting code lives in `./crates/privy-openapi`. |
| 126 | +
|
| 127 | +### Code Generation (`build.rs`) |
| 128 | +
|
| 129 | +The `build.rs` script is responsible for generating the typed subclients that provide a convenient, resource-oriented interface. The process works as follows: |
| 130 | +
|
| 131 | +1. **Base Client Generation:** The script parses code with `progenitor` and gets an AST. |
| 132 | +2. **Configuration Parsing:** It reads `stainless.yml` to understand the desired structure of the final client. This YAML file defines resources (like `wallets`, `users`), maps method names to API endpoints, and defines nested subclients (e.g., `wallets().rpc()`). |
| 133 | +3. **Subclient Generation:** The script then parses the AST from progenitor, pulls the function signatures, and stamps out delegatory methods that forward the call onto the raw method on the base client, following the `stainless.yml` configuration, to generate specialized **subclients** (e.g., `WalletsClient`, `UsersClient`). These subclients wrap the base `Client` and provide a more ergonomic API surface consistent with the other SDKs. |
| 134 | +4. **Main Client Extension:** Finally, it adds accessor methods to the main `PrivyClient` (e.g., `privy_client.wallets()`) that return instances of the generated subclients. |
| 135 | +
|
| 136 | +If you make changes to either `openapi.json` or `stainless.yml`, `cargo` will automatically re-run this build script to regenerate the clients. |
| 137 | +
|
| 138 | +> Note: while we technically run progenitor _twice_, the build.rs file never |
| 139 | +actually writes those files anywhere. It is only used to pull out the AST |
| 140 | +so that we can automatically generate the sub-clients with the appropriate |
| 141 | +function signatures. |
| 142 | +
|
| 143 | +### Rest |
| 144 | +
|
| 145 | +Otherwise, this is just your standard (well-documented) rust crate. We provide |
| 146 | +a few manual impls for functions in the sub-clients which is managed in the |
| 147 | +subclients folder. |
| 148 | +
|
| 149 | +*** |
| 150 | +
|
| 151 | +## Contribution Workflow |
| 152 | +
|
| 153 | +To ensure code quality and consistency, please follow these steps before submitting a pull request. |
| 154 | +
|
| 155 | +### 1. Formatting |
| 156 | +
|
| 157 | +This project uses `rustfmt` to maintain a consistent code style. The configuration is defined in `rustfmt.toml`. Before committing, please format your code: |
| 158 | +
|
| 159 | +```bash |
| 160 | +cargo fmt --all |
| 161 | +``` |
| 162 | +
|
| 163 | +While not required, you can also format the rustdoc code using `rustfmt` but only on rust nightly: |
| 164 | +
|
| 165 | +```bash |
| 166 | +cargo +nightly fmt --all |
| 167 | +``` |
| 168 | +
|
| 169 | +### 2. Linting |
| 170 | +
|
| 171 | +We use clippy to catch common mistakes and improve code quality. Run clippy with the following command: |
| 172 | +
|
| 173 | +```bash |
| 174 | +cargo clippy --all-targets |
| 175 | +``` |
| 176 | +
|
| 177 | +### 3. Testing |
| 178 | +
|
| 179 | +Ensure all tests pass before submitting: |
| 180 | +
|
| 181 | +```bash |
| 182 | +cargo test --all |
| 183 | +``` |
| 184 | +
|
| 185 | +### 4. Committing Your Changes |
| 186 | +
|
| 187 | +This project uses release-plz to automate releases and changelog generation based on commit messages. Please follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification to help categorize changes in the changelog and release notes. Anything that is not a conventional commit will be just included under the 'other' header. |
| 188 | +
|
| 189 | +- `feat:` A new feature (e.g., `feat: add support for fiat on-ramping`) |
| 190 | +- `fix:` A bug fix (e.g., `fix: correct serialization of wallet update requests`) |
| 191 | +- `docs:` Changes to documentation only |
| 192 | +- `style:` Formatting changes, no code logic changes |
| 193 | +- `refactor:` Code changes that neither fix a bug nor add a feature |
| 194 | +- `test:` Adding or refactoring tests |
| 195 | +- `chore:` Build process or tooling changes |
| 196 | +
|
| 197 | +### 5. Submitting a Pull Request |
| 198 | +
|
| 199 | +Once your changes are ready, push them to your fork and open a pull request. Please provide a clear description of the changes and link any relevant issues. Ensure that all checks (formatting, linting, testing) pass in CI. Note that all PRs submitted are assumed to be licensed under the same conditions as the rest of the repository. |
| 200 | +
|
| 201 | +*** |
| 202 | +
|
| 203 | +## Development Policies |
| 204 | +
|
| 205 | +### Rust Version Policy (MSRV) |
| 206 | +
|
| 207 | +The Rust toolchain version for development and CI will not be less than two major versions behind the current stable release. This ensures a balance between modern language features and ecosystem stability. |
| 208 | +
|
| 209 | +### `Cargo.lock` Policy |
| 210 | +
|
| 211 | +> **Note:** The convention for this has recently changed in Rust. |
| 212 | +
|
| 213 | +Previously, many recommended not committing Cargo.lock into the repo for libraries since potential version mismatches would be highlighted earlier, however this opinion is now changing. For that reason, this project **tracks the `Cargo.lock` file**. This ensures that all developers and the CI environment are using the exact same dependency versions, leading to more reproducible builds. |
| 214 | +
|
| 215 | +For more, see [this GitHub issue](https://github.com/rust-lang/cargo/issues/315). |
0 commit comments