npmctl-godaddy 0.3.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ Apache-2.0
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: npmctl-godaddy
3
+ Version: 0.3.6
4
+ Summary: GoDaddy DNS provider extension for npmctl.
5
+ Keywords: godaddy,dns,nginx-proxy-manager,npmctl
6
+ Author: Jacob Stewart
7
+ Author-email: Jacob Stewart <jacob@swarmauri.com>
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 1 - Planning
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Internet :: Name Service (DNS)
20
+ Classifier: Topic :: System :: Systems Administration
21
+ Requires-Dist: requests>=2.32.0
22
+ Requires-Python: >=3.10, <3.15
23
+ Project-URL: Homepage, https://github.com/groupsum/npmctl
24
+ Project-URL: Repository, https://github.com/groupsum/npmctl
25
+ Project-URL: Documentation, https://github.com/groupsum/npmctl/tree/master/packages/npmctl-godaddy
26
+ Project-URL: Issues, https://github.com/groupsum/npmctl/issues
27
+ Description-Content-Type: text/markdown
28
+
29
+ <h1 align="center">npmctl-godaddy</h1>
30
+
31
+ <p align="center"><strong>GoDaddy DNS provider plugin for npmctl</strong></p>
32
+
33
+ <p align="center">
34
+ Extend <code>npmctl</code> with GoDaddy-backed DNS record management for declarative workflows, provider discovery, and DNS-aware automation.
35
+ </p>
36
+
37
+ <p align="center">
38
+ <a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/v/npmctl-godaddy.svg" alt="PyPI version"></a>
39
+ <a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/pyversions/npmctl-godaddy.svg" alt="Python versions"></a>
40
+ <a href="https://github.com/groupsum/npmctl/actions/workflows/ci.yml"><img src="https://github.com/groupsum/npmctl/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
41
+ <a href="https://github.com/groupsum/npmctl/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="Apache 2.0 License"></a>
42
+ </p>
43
+
44
+ <p align="center">
45
+ <a href="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md/"><img src="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md.svg?label=npmctl-godaddy%20package%20hits" alt="npmctl-godaddy package hits"></a>
46
+ <a href="https://pepy.tech/projects/npmctl-godaddy"><img src="https://static.pepy.tech/badge/npmctl-godaddy" alt="npmctl-godaddy downloads"></a>
47
+ </p>
48
+
49
+ <p align="center">
50
+ <img src="https://raw.githubusercontent.com/groupsum/npmctl/master/docs/images/marketing/npmctl-architecture-infographic.png" alt="npmctl architecture infographic">
51
+ </p>
52
+
53
+ `npmctl-godaddy` is the GoDaddy DNS provider package for `npmctl`. Install it when you want desired-state DNS records or DNS diagnostics to resolve through GoDaddy instead of using only the base `npmctl` package.
54
+
55
+ ## Supported Python Versions
56
+
57
+ `npmctl-godaddy` supports Python `3.10`, `3.11`, `3.12`, `3.13`, and `3.14`.
58
+
59
+ ## Why npmctl-godaddy
60
+
61
+ - Adds GoDaddy DNS provider discovery to `npmctl`
62
+ - Lets DNS workflows live beside proxy and certificate desired state
63
+ - Keeps GoDaddy API keys out of the core CLI package
64
+ - Supports operator diagnostics through `npmctl dns doctor`
65
+ - Documents GoDaddy's record-set replacement behavior for safer automation
66
+
67
+ ## FAQ
68
+
69
+ ### What is npmctl-godaddy?
70
+
71
+ **Answer:** `npmctl-godaddy` is a plugin package that teaches `npmctl` how to talk to the GoDaddy Domains API for DNS record operations and DNS provider diagnostics.
72
+
73
+ ### When do I need npmctl-godaddy?
74
+
75
+ **Answer:** You need `npmctl-godaddy` when your `npmctl` workflow includes GoDaddy-managed DNS records or when you want `npmctl` to validate GoDaddy DNS connectivity and credentials.
76
+
77
+ ### Does npmctl-godaddy work without npmctl?
78
+
79
+ **Answer:** No. `npmctl-godaddy` is an extension package for `npmctl`, not a standalone CLI.
80
+
81
+ ### Can npmctl-godaddy set A and CNAME records?
82
+
83
+ **Answer:** Yes. GoDaddy's Domains API supports A and CNAME records. Its DNS mutation endpoint replaces all records for one `{type, name}` pair, so preserve existing values when managing multi-value records.
84
+
85
+ ### What credentials are required?
86
+
87
+ **Answer:** GoDaddy API access requires `GODADDY_API_KEY` and `GODADDY_API_SECRET`. Account protection, domain locks, or product eligibility can still block DNS mutations even when credentials are valid.
88
+
89
+ ## Install
90
+
91
+ Install the base CLI and the GoDaddy provider package together:
92
+
93
+ ```bash
94
+ pipx install npmctl
95
+ pipx inject npmctl npmctl-godaddy
96
+ npmctl plugins list
97
+ ```
98
+
99
+ With `uv`:
100
+
101
+ ```bash
102
+ uv tool install npmctl
103
+ uv tool install npmctl-godaddy
104
+ npmctl plugins list
105
+ ```
106
+
107
+ Inside a virtual environment:
108
+
109
+ ```bash
110
+ python -m venv .venv
111
+ . .venv/bin/activate
112
+ python -m pip install npmctl npmctl-godaddy
113
+ npmctl plugins list
114
+ ```
115
+
116
+ ## Configure GoDaddy
117
+
118
+ Set the required environment variables:
119
+
120
+ ```bash
121
+ export GODADDY_API_KEY=your-api-key
122
+ export GODADDY_API_SECRET=your-api-secret
123
+ ```
124
+
125
+ Optional for tests or alternate endpoints:
126
+
127
+ ```bash
128
+ export GODADDY_API_BASE_URL=https://api.godaddy.com
129
+ ```
130
+
131
+ ## Verify Plugin Discovery
132
+
133
+ Check that `npmctl` can discover the provider:
134
+
135
+ ```bash
136
+ npmctl plugins list
137
+ npmctl dns doctor --provider godaddy
138
+ ```
139
+
140
+ ## Minimal DNS Workflow
141
+
142
+ Once the provider is installed and configured, `npmctl` can validate or diagnose GoDaddy-backed DNS behavior through the base CLI:
143
+
144
+ ```bash
145
+ npmctl dns providers
146
+ npmctl dns zones --provider godaddy
147
+ npmctl dns records --provider godaddy --zone example.com
148
+ ```
149
+
150
+ ## GoDaddy API Surface
151
+
152
+ The provider follows the GoDaddy Domains API DNS record surface:
153
+
154
+ - `GET /v1/domains`: discover domains in the account.
155
+ - `GET /v1/domains/{domain}/records`: list all DNS records for one domain.
156
+ - `GET /v1/domains/{domain}/records/{type}/{name}`: list records for one type and name.
157
+ - `PUT /v1/domains/{domain}/records/{type}/{name}`: replace the full record set for one type and name.
158
+ - `DELETE /v1/domains/{domain}/records/{type}/{name}`: delete records for one type and name.
159
+
160
+ ## Programmatic Record Operations
161
+
162
+ `create_record()` is a convenience wrapper that replaces a `{type, name}` pair with one record. Use `replace_records()` when preserving multiple values for the same record name and type:
163
+
164
+ ```python
165
+ from npmctl_godaddy import GoDaddyClient, GoDaddyConfig
166
+
167
+ client = GoDaddyClient(GoDaddyConfig.from_env())
168
+ client.create_record("example.com", type="A", name="www", value="192.0.2.10", ttl=600)
169
+ client.replace_records(
170
+ "example.com",
171
+ type="CNAME",
172
+ name="app",
173
+ records=[{"data": "target.example.net", "ttl": 600}],
174
+ )
175
+ client.delete_records("example.com", type="A", name="www")
176
+ ```
177
+
178
+ ## Safety Notes
179
+
180
+ - GoDaddy `PUT` replaces all records for the selected `{type, name}` pair.
181
+ - Account-level domain locks, premium DNS status, protection settings, or product eligibility may block API changes even when credentials are valid.
182
+ - Use least-privilege keys where available and avoid broad automation over unrelated domains.
183
+ - Use npmctl owner metadata for desired DNS records so future apply support can remain owner-scoped.
184
+
185
+ ## More Documentation
186
+
187
+ - Related PyPI package: https://pypi.org/project/npmctl/
188
+ - Repository: https://github.com/groupsum/npmctl
189
+ - DNS provider docs: https://github.com/groupsum/npmctl/tree/master/docs/dns-providers.md
@@ -0,0 +1,161 @@
1
+ <h1 align="center">npmctl-godaddy</h1>
2
+
3
+ <p align="center"><strong>GoDaddy DNS provider plugin for npmctl</strong></p>
4
+
5
+ <p align="center">
6
+ Extend <code>npmctl</code> with GoDaddy-backed DNS record management for declarative workflows, provider discovery, and DNS-aware automation.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/v/npmctl-godaddy.svg" alt="PyPI version"></a>
11
+ <a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/pyversions/npmctl-godaddy.svg" alt="Python versions"></a>
12
+ <a href="https://github.com/groupsum/npmctl/actions/workflows/ci.yml"><img src="https://github.com/groupsum/npmctl/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
13
+ <a href="https://github.com/groupsum/npmctl/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="Apache 2.0 License"></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md/"><img src="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md.svg?label=npmctl-godaddy%20package%20hits" alt="npmctl-godaddy package hits"></a>
18
+ <a href="https://pepy.tech/projects/npmctl-godaddy"><img src="https://static.pepy.tech/badge/npmctl-godaddy" alt="npmctl-godaddy downloads"></a>
19
+ </p>
20
+
21
+ <p align="center">
22
+ <img src="https://raw.githubusercontent.com/groupsum/npmctl/master/docs/images/marketing/npmctl-architecture-infographic.png" alt="npmctl architecture infographic">
23
+ </p>
24
+
25
+ `npmctl-godaddy` is the GoDaddy DNS provider package for `npmctl`. Install it when you want desired-state DNS records or DNS diagnostics to resolve through GoDaddy instead of using only the base `npmctl` package.
26
+
27
+ ## Supported Python Versions
28
+
29
+ `npmctl-godaddy` supports Python `3.10`, `3.11`, `3.12`, `3.13`, and `3.14`.
30
+
31
+ ## Why npmctl-godaddy
32
+
33
+ - Adds GoDaddy DNS provider discovery to `npmctl`
34
+ - Lets DNS workflows live beside proxy and certificate desired state
35
+ - Keeps GoDaddy API keys out of the core CLI package
36
+ - Supports operator diagnostics through `npmctl dns doctor`
37
+ - Documents GoDaddy's record-set replacement behavior for safer automation
38
+
39
+ ## FAQ
40
+
41
+ ### What is npmctl-godaddy?
42
+
43
+ **Answer:** `npmctl-godaddy` is a plugin package that teaches `npmctl` how to talk to the GoDaddy Domains API for DNS record operations and DNS provider diagnostics.
44
+
45
+ ### When do I need npmctl-godaddy?
46
+
47
+ **Answer:** You need `npmctl-godaddy` when your `npmctl` workflow includes GoDaddy-managed DNS records or when you want `npmctl` to validate GoDaddy DNS connectivity and credentials.
48
+
49
+ ### Does npmctl-godaddy work without npmctl?
50
+
51
+ **Answer:** No. `npmctl-godaddy` is an extension package for `npmctl`, not a standalone CLI.
52
+
53
+ ### Can npmctl-godaddy set A and CNAME records?
54
+
55
+ **Answer:** Yes. GoDaddy's Domains API supports A and CNAME records. Its DNS mutation endpoint replaces all records for one `{type, name}` pair, so preserve existing values when managing multi-value records.
56
+
57
+ ### What credentials are required?
58
+
59
+ **Answer:** GoDaddy API access requires `GODADDY_API_KEY` and `GODADDY_API_SECRET`. Account protection, domain locks, or product eligibility can still block DNS mutations even when credentials are valid.
60
+
61
+ ## Install
62
+
63
+ Install the base CLI and the GoDaddy provider package together:
64
+
65
+ ```bash
66
+ pipx install npmctl
67
+ pipx inject npmctl npmctl-godaddy
68
+ npmctl plugins list
69
+ ```
70
+
71
+ With `uv`:
72
+
73
+ ```bash
74
+ uv tool install npmctl
75
+ uv tool install npmctl-godaddy
76
+ npmctl plugins list
77
+ ```
78
+
79
+ Inside a virtual environment:
80
+
81
+ ```bash
82
+ python -m venv .venv
83
+ . .venv/bin/activate
84
+ python -m pip install npmctl npmctl-godaddy
85
+ npmctl plugins list
86
+ ```
87
+
88
+ ## Configure GoDaddy
89
+
90
+ Set the required environment variables:
91
+
92
+ ```bash
93
+ export GODADDY_API_KEY=your-api-key
94
+ export GODADDY_API_SECRET=your-api-secret
95
+ ```
96
+
97
+ Optional for tests or alternate endpoints:
98
+
99
+ ```bash
100
+ export GODADDY_API_BASE_URL=https://api.godaddy.com
101
+ ```
102
+
103
+ ## Verify Plugin Discovery
104
+
105
+ Check that `npmctl` can discover the provider:
106
+
107
+ ```bash
108
+ npmctl plugins list
109
+ npmctl dns doctor --provider godaddy
110
+ ```
111
+
112
+ ## Minimal DNS Workflow
113
+
114
+ Once the provider is installed and configured, `npmctl` can validate or diagnose GoDaddy-backed DNS behavior through the base CLI:
115
+
116
+ ```bash
117
+ npmctl dns providers
118
+ npmctl dns zones --provider godaddy
119
+ npmctl dns records --provider godaddy --zone example.com
120
+ ```
121
+
122
+ ## GoDaddy API Surface
123
+
124
+ The provider follows the GoDaddy Domains API DNS record surface:
125
+
126
+ - `GET /v1/domains`: discover domains in the account.
127
+ - `GET /v1/domains/{domain}/records`: list all DNS records for one domain.
128
+ - `GET /v1/domains/{domain}/records/{type}/{name}`: list records for one type and name.
129
+ - `PUT /v1/domains/{domain}/records/{type}/{name}`: replace the full record set for one type and name.
130
+ - `DELETE /v1/domains/{domain}/records/{type}/{name}`: delete records for one type and name.
131
+
132
+ ## Programmatic Record Operations
133
+
134
+ `create_record()` is a convenience wrapper that replaces a `{type, name}` pair with one record. Use `replace_records()` when preserving multiple values for the same record name and type:
135
+
136
+ ```python
137
+ from npmctl_godaddy import GoDaddyClient, GoDaddyConfig
138
+
139
+ client = GoDaddyClient(GoDaddyConfig.from_env())
140
+ client.create_record("example.com", type="A", name="www", value="192.0.2.10", ttl=600)
141
+ client.replace_records(
142
+ "example.com",
143
+ type="CNAME",
144
+ name="app",
145
+ records=[{"data": "target.example.net", "ttl": 600}],
146
+ )
147
+ client.delete_records("example.com", type="A", name="www")
148
+ ```
149
+
150
+ ## Safety Notes
151
+
152
+ - GoDaddy `PUT` replaces all records for the selected `{type, name}` pair.
153
+ - Account-level domain locks, premium DNS status, protection settings, or product eligibility may block API changes even when credentials are valid.
154
+ - Use least-privilege keys where available and avoid broad automation over unrelated domains.
155
+ - Use npmctl owner metadata for desired DNS records so future apply support can remain owner-scoped.
156
+
157
+ ## More Documentation
158
+
159
+ - Related PyPI package: https://pypi.org/project/npmctl/
160
+ - Repository: https://github.com/groupsum/npmctl
161
+ - DNS provider docs: https://github.com/groupsum/npmctl/tree/master/docs/dns-providers.md
@@ -0,0 +1,39 @@
1
+ [project]
2
+ name = "npmctl-godaddy"
3
+ version = "0.3.6"
4
+ description = "GoDaddy DNS provider extension for npmctl."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10,<3.15"
7
+ license = "Apache-2.0"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
10
+ classifiers = [
11
+ "Development Status :: 1 - Planning",
12
+ "Intended Audience :: System Administrators",
13
+ "License :: OSI Approved :: Apache Software License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
20
+ "Topic :: Internet :: Name Service (DNS)",
21
+ "Topic :: System :: Systems Administration",
22
+ ]
23
+ keywords = ["godaddy", "dns", "nginx-proxy-manager", "npmctl"]
24
+ dependencies = [
25
+ "requests>=2.32.0",
26
+ ]
27
+
28
+ [project.entry-points."npmctl.dns_providers"]
29
+ godaddy = "npmctl_godaddy.provider:GoDaddyDnsProvider"
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/groupsum/npmctl"
33
+ Repository = "https://github.com/groupsum/npmctl"
34
+ Documentation = "https://github.com/groupsum/npmctl/tree/master/packages/npmctl-godaddy"
35
+ Issues = "https://github.com/groupsum/npmctl/issues"
36
+
37
+ [build-system]
38
+ requires = ["uv-build>=0.11.8,<0.12"]
39
+ build-backend = "uv_build"
@@ -0,0 +1,7 @@
1
+ """GoDaddy DNS extension for npmctl."""
2
+
3
+ from npmctl_godaddy.client import GoDaddyClient
4
+ from npmctl_godaddy.config import GoDaddyConfig
5
+ from npmctl_godaddy.provider import GoDaddyDnsProvider
6
+
7
+ __all__ = ["GoDaddyClient", "GoDaddyConfig", "GoDaddyDnsProvider"]
@@ -0,0 +1,78 @@
1
+ """Small GoDaddy Domains API client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Mapping
6
+
7
+ import requests
8
+
9
+ from npmctl_godaddy.config import GoDaddyConfig
10
+ from npmctl_godaddy.errors import GoDaddyError
11
+ from npmctl_godaddy.models import GoDaddyRecord
12
+
13
+
14
+ class GoDaddyClient:
15
+ """HTTP client for GoDaddy domain DNS records."""
16
+
17
+ def __init__(self, config: GoDaddyConfig, *, timeout_s: float = 15.0) -> None:
18
+ self.config = config
19
+ self.timeout_s = timeout_s
20
+ self.session = requests.Session()
21
+
22
+ def zones(self) -> tuple[str, ...]:
23
+ data = self._request("GET", "/v1/domains")
24
+ return tuple(sorted(str(item.get("domain", "")).lower().rstrip(".") for item in data if item.get("domain")))
25
+
26
+ def records(self, zone: str) -> tuple[GoDaddyRecord, ...]:
27
+ data = self._request("GET", f"/v1/domains/{_zone(zone)}/records")
28
+ return tuple(GoDaddyRecord.from_mapping(item) for item in data)
29
+
30
+ def records_by_name(self, zone: str, *, type: str, name: str) -> tuple[GoDaddyRecord, ...]:
31
+ data = self._request("GET", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}")
32
+ return tuple(GoDaddyRecord.from_mapping({**item, "type": type.upper(), "name": name}) for item in data)
33
+
34
+ def create_record(self, zone: str, *, type: str, name: str, value: str, ttl: int | None = None) -> None:
35
+ record: dict[str, object] = {"data": value}
36
+ if ttl is not None:
37
+ record["ttl"] = ttl
38
+ self.replace_records(zone, type=type, name=name, records=[record])
39
+
40
+ def replace_records(self, zone: str, *, type: str, name: str, records: list[Mapping[str, object]]) -> None:
41
+ payload = [_record_payload(item) for item in records]
42
+ self._request("PUT", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}", json=payload)
43
+
44
+ def delete_records(self, zone: str, *, type: str, name: str) -> None:
45
+ self._request("DELETE", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}")
46
+
47
+ def _request(self, method: str, path: str, **kwargs: Any) -> Any:
48
+ response = self.session.request(
49
+ method,
50
+ f"{self.config.api_base_url}{path}",
51
+ headers={"Authorization": f"sso-key {self.config.api_key}:{self.config.api_secret}"},
52
+ timeout=self.timeout_s,
53
+ **kwargs,
54
+ )
55
+ if response.status_code < 200 or response.status_code >= 300:
56
+ raise GoDaddyError(f"GoDaddy API failed: HTTP {response.status_code}")
57
+ if response.status_code == 204:
58
+ return []
59
+ try:
60
+ return response.json()
61
+ except ValueError as exc:
62
+ raise GoDaddyError("GoDaddy API returned invalid JSON") from exc
63
+
64
+
65
+ def _record_payload(item: Mapping[str, object]) -> dict[str, object]:
66
+ payload = {"data": item["data"]}
67
+ for key in ("ttl", "priority", "port", "protocol", "service", "weight"):
68
+ if key in item and item[key] is not None:
69
+ payload[key] = item[key]
70
+ return payload
71
+
72
+
73
+ def _name(name: str) -> str:
74
+ return name.strip().lower().rstrip(".")
75
+
76
+
77
+ def _zone(zone: str) -> str:
78
+ return zone.strip().lower().rstrip(".")
@@ -0,0 +1,32 @@
1
+ """Configuration loading for the GoDaddy DNS provider."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass
7
+ from typing import Mapping
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class GoDaddyConfig:
12
+ """GoDaddy API configuration."""
13
+
14
+ api_key: str
15
+ api_secret: str
16
+ api_base_url: str = "https://api.godaddy.com"
17
+
18
+ @classmethod
19
+ def from_env(cls, env: Mapping[str, str] | None = None) -> GoDaddyConfig:
20
+ values = os.environ if env is None else env
21
+ required = {"api_key": values.get("GODADDY_API_KEY"), "api_secret": values.get("GODADDY_API_SECRET")}
22
+ missing = [name for name, value in required.items() if not value]
23
+ if missing:
24
+ raise ValueError(f"missing GoDaddy config: {', '.join(missing)}")
25
+ return cls(
26
+ api_key=str(required["api_key"]),
27
+ api_secret=str(required["api_secret"]),
28
+ api_base_url=values.get("GODADDY_API_BASE_URL", "https://api.godaddy.com"),
29
+ )
30
+
31
+ def redacted(self) -> dict[str, str | bool]:
32
+ return {"api_key": bool(self.api_key), "api_secret": bool(self.api_secret), "api_base_url": self.api_base_url}
@@ -0,0 +1,7 @@
1
+ """GoDaddy provider errors."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ class GoDaddyError(RuntimeError):
7
+ """Raised when the GoDaddy API returns an error."""
@@ -0,0 +1,43 @@
1
+ """GoDaddy DNS response models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any, Mapping
7
+
8
+
9
+ @dataclass(frozen=True, slots=True)
10
+ class GoDaddyRecord:
11
+ """One GoDaddy DNS record."""
12
+
13
+ name: str
14
+ type: str
15
+ value: str
16
+ ttl: int | None = None
17
+ priority: int | None = None
18
+
19
+ @classmethod
20
+ def from_mapping(cls, raw: Mapping[str, Any]) -> GoDaddyRecord:
21
+ return cls(
22
+ name=str(raw.get("name", "")).lower().rstrip("."),
23
+ type=str(raw.get("type", "")).upper(),
24
+ value=str(raw.get("data", "")),
25
+ ttl=_optional_int(raw.get("ttl")),
26
+ priority=_optional_int(raw.get("priority")),
27
+ )
28
+
29
+ def to_dict(self) -> dict[str, str | int | None]:
30
+ return {
31
+ "id": None,
32
+ "name": self.name,
33
+ "type": self.type,
34
+ "value": self.value,
35
+ "ttl": self.ttl,
36
+ "priority": self.priority,
37
+ }
38
+
39
+
40
+ def _optional_int(value: Any) -> int | None:
41
+ if value in (None, ""):
42
+ return None
43
+ return int(value)
@@ -0,0 +1,27 @@
1
+ """npmctl DNS provider implementation for GoDaddy."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from npmctl_godaddy.client import GoDaddyClient
6
+ from npmctl_godaddy.config import GoDaddyConfig
7
+
8
+
9
+ class GoDaddyDnsProvider:
10
+ """DNS provider backed by the GoDaddy Domains API."""
11
+
12
+ name = "godaddy"
13
+
14
+ def __init__(self, client: GoDaddyClient | None = None) -> None:
15
+ self._client = client
16
+
17
+ @property
18
+ def client(self) -> GoDaddyClient:
19
+ if self._client is None:
20
+ self._client = GoDaddyClient(GoDaddyConfig.from_env())
21
+ return self._client
22
+
23
+ def zones(self) -> tuple[str, ...]:
24
+ return self.client.zones()
25
+
26
+ def records(self, zone: str) -> tuple[dict[str, object], ...]:
27
+ return tuple(record.to_dict() for record in self.client.records(zone))