octodns-metaname: Add domain registration routine to MetanameClient

Summary

Add register_domain() and check_domain() methods to MetanameClient in the octodns-metaname module, making domain registration a first-class operation alongside DNS record management. The standalone scripts/metaname_register.py script in this repo would then be deprecated in favour of the module method.

Motivation

  • The module already has all the plumbing: JSON-RPC infrastructure (_rpc), secret resolution (secrets.py), and a Contact dataclass with to_payload() serialization
  • Registration currently requires a separate standalone script with its own secret-resolution logic and error handling
  • bundling it into the client makes the module a one-stop shop for Metaname operations

What needs doing

0. Verify the RPC contract FIRST

Do not lock the register_domain() signature until the actual Metaname register_domain_name RPC method and parameter schema have been confirmed against the Metaname API docs. The signature sketch below is provisional — the real implementation must match what the API actually expects.

1. Add check_domain() to MetanameClient

def check_domain(self, domain: str) -> dict:
    """Check domain availability via Metaname.

    Returns the raw API response. Callers inspect the result to
    determine whether the domain is available, registered, etc.
    """
    return self._rpc("check_domain_name", [domain])

2. Add register_domain() to MetanameClient — WITH SAFETY RAILS

def register_domain(
    self,
    domain: str,
    *,
    term: int = 12,          # months (Metaname registration term unit)
    confirm: bool = False,   # MUST be True — guardrail against accidental registration
    contacts: dict | None = None,
    nameservers: list[str] | None = None,
) -> dict:

Safety rails (required before merge):

  • confirm=True is required. Passing confirm=False raises ValueError. Domain registration costs real money and is irreversible — this prevents accidental calls from agent/automation workflows.
  • register_domain() internally calls check_domain() and refuses to proceed if the domain is already taken (raises a descriptive error), rather than trusting the caller to check first.

Contact handling: Metaname expects contacts keyed by role (registrant, admin, technical). The client already has _default_contact() (static method on MetanameClient) plus the Contact dataclass — reuse them.

3. Optional: CLI entry point

Consider a lightweight python -m octodns_metaname register entry point via __main__.py or a register() function exposed from the package. The CLI should also require a --confirm flag.

4. Tests

  • Mock _rpc to verify correct JSON-RPC method + parameter shape
  • Test check_domain returns availability
  • Test register_domain constructs correct contact/nameserver payloads
  • Test that confirm=False raises ValueError
  • Test that registration of an already-registered domain raises (via mocked check_domain response)
  • Test that missing secrets produce MissingSecret (not bare RuntimeError)

5. Concrete deprecation path for scripts/metaname_register.py

Do not delete the script immediately. The deprecation path:

  1. This release (v0.2.0): Rewrite metaname_register.py as a thin wrapper that imports MetanameClient.register_domain from the module and emits a DeprecationWarning. The script keeps working (same CLI interface) so existing automation is not broken.
  2. Next release (v0.3.0): Delete the script. Users should call MetanameClient directly.

References

  • Metaname JSON-RPC API docs — verify register_domain_name method and parameter schema before implementing
  • Existing MetanameClient._rpc() + _default_contact() + Contact.to_payload()
  • Module repo: https://github.com/startmeup-nz/octodns-metaname
  • Deprecated script: public/opsdev.nz/scripts/metaname_register.py
Edited by John Billings