voip-ms 0.1.3

Async client for the voip.ms REST API
Documentation
# Development Guide

This document covers contributor and maintainer workflows for voip-ms.

## Regenerating the API surface

`src/generated.rs` is produced by the `xtask` workspace member from
three committed inputs:

* `tools/server.wsdl` — method list, parameter names, parameter types.
* `tools/api-responses.json` — inferred response shape per method,
  extracted from the official HTML docs by `cargo xtask
  extract-responses`.
* `tools/api-response-overrides.json` — hand-edited corrections to the
  above (per-path scalar retypes or full shape replacement).

### Picking up new methods (WSDL change)

```bash
curl -o tools/server.wsdl https://voip.ms/api/v1/server.wsdl
cargo xtask gen
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
```

### Refreshing response shapes (HTML docs change)

voip.ms's `apidocs.php` page is Cloudflare-gated, so the HTML has to be
saved manually:

1. Log into the voip.ms customer portal in a browser.
2. Open `https://voip.ms/m/apidocs.php` and save the rendered HTML to
   `target/apidocs.html` (or any path under `target/`, which is
   gitignored).
3. Re-run the extractor and inspect the diff:

   ```bash
   cargo xtask extract-responses target/apidocs.html
   git diff tools/api-responses.json
   ```

4. If a scalar landed with the wrong type (a phone-number `did` parsed
   as `integer`, a `0/1` flag parsed as `integer`, …) or a method's
   Output block failed to parse, edit
   `tools/api-response-overrides.json` — never edit
   `tools/api-responses.json` by hand.
5. Regenerate and run the quality gate:

   ```bash
   cargo xtask gen
   cargo fmt --all -- --check
   cargo clippy --workspace --all-targets -- -D warnings
   cargo test --workspace --all-targets
   ```

The overrides schema lives in
[xtask/src/overrides.rs](xtask/src/overrides.rs) — see the module docs
for the path grammar.

## Releasing

Publishing is automated via [.github/workflows/release.yaml](.github/workflows/release.yaml).

1. Ensure Cargo.toml has the target version.
2. Move release notes from Unreleased into a versioned section in CHANGELOG.md.
3. Push a tag in the form vX.Y.Z.

```bash
git tag v0.1.1
git push origin v0.1.1
```

On tag push, the workflow verifies the tag version matches Cargo.toml, runs
fmt/clippy/tests, performs cargo publish --dry-run, publishes to crates.io
using CRATES_IO_TOKEN, and creates a GitHub release.

## Testing strategy

1. Integration tests in `tests/client.rs` use `wiremock` to assert:
	 * a success response surfaces the full envelope verbatim
	 * a non-success status maps to `Error::Api`
	 * a 5xx status maps to `Error::Http`
	 * a missing `status` field maps to `Error::InvalidResponse`
	 * optional `None` fields are not sent in query parameters
	 * `Client::call` supports follow-on typed deserialization
2. Coverage target is around 80% for hand-written code paths (`client.rs`
	 and `error.rs`). `generated.rs` is mechanical and validated transitively
	 through representative integration tests.
3. Live calls to voip.ms are intentionally excluded from CI because they
	 require real credentials and account state.

## Live API verification workflow

The repository includes a dedicated workflow for optional live verification:
`.github/workflows/live-api-verify.yaml`.

Use this workflow for release-time checks or on-demand execution via
`workflow_dispatch`. It is intentionally separate from `rust-ci.yaml` so pull
requests remain deterministic and credential-free.

### Required account configuration

1. Create a dedicated voip.ms sandbox account (or isolated reseller test scope).
2. Enable API access and generate API credentials.
3. Allow-list the GitHub runner egress IP(s) on the voip.ms API page.
4. For SMS checks, provide at least one DID with SMS available and enabled.
5. For sub-account lifecycle checks, ensure the sandbox has permission to
   create and delete sub-accounts.

### Required GitHub Actions secrets

* `VOIP_MS_USERNAME`
* `VOIP_MS_PASSWORD`

Optional fixture secrets used by opt-in checks:

* `VOIP_MS_TEST_DID`
* `VOIP_MS_SMS_DST`
* `VOIP_MS_SMS_MESSAGE`

### Safety model

The live harness defaults to read-only smoke checks.

State-changing checks require both:

* `LIVE_VERIFY_MODE=extended`
* `LIVE_VERIFY_ALLOW_STATE_CHANGES=true`

Potentially costly checks (for example sending SMS) require both:

* `LIVE_VERIFY_ENABLE_SMS_SEND_CHECK=true`
* `LIVE_VERIFY_ALLOW_COSTLY=true`

This dual-gate model prevents accidental financial transactions and keeps
release verification safe by default.

## CI/CD workflows

* `rust-ci.yaml` runs on pull requests and pushes to `main`:
	* `cargo fmt --all -- --check`
	* `cargo clippy --all -- -D warnings`
	* `cargo test` with coverage instrumentation
	* coverage summary posted to pull requests via
		`ecliptical/covdir-report-action`
* `dependabot-automerge.yaml` auto-approves and auto-merges safe Cargo
	updates from Dependabot.
* `release.yaml` runs on `v*` tags:
	* validates tag version against Cargo.toml
	* runs fmt, clippy, tests, and publish dry-run checks
	* publishes to crates.io with `CRATES_IO_TOKEN`
	* creates a GitHub release from the tag
* `live-api-verify.yaml` supports optional live verification:
	* `workflow_dispatch` for operator-invokable smoke or extended checks
	* `v*` tag trigger for release-time smoke checks
	* explicit safety gates for state-changing or costly operations