namecheap-python 0.1.0__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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Adrian
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,346 @@
1
+ Metadata-Version: 2.3
2
+ Name: namecheap-python
3
+ Version: 0.1.0
4
+ Summary: A Python SDK for the Namecheap API
5
+ License: MIT
6
+ Keywords: namecheap,domain,dns,api,sdk
7
+ Author: Adrian Galilea
8
+ Author-email: adriangalilea@gmail.com
9
+ Requires-Python: >=3.7
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: Name Service (DNS)
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Dist: python-dotenv (>=0.19.0)
25
+ Requires-Dist: requests (>=2.25.0)
26
+ Project-URL: Documentation, https://github.com/adriangalilea/namecheap-python#readme
27
+ Project-URL: Repository, https://github.com/adriangalilea/namecheap-python
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Namecheap Python SDK
31
+
32
+ A Python wrapper for the Namecheap API that allows developers to interact programmatically with Namecheap's domain registration and management services.
33
+
34
+ I needed an MCP, so I needed an API, I checked and the previous python API SDK for Namecheap was abandoned, so I went ahead and did this one.
35
+
36
+ ## Project Focus
37
+
38
+ This SDK currently focuses on domain management functionality of the Namecheap API, including:
39
+ - Domain availability checking
40
+ - Domain registration and renewal
41
+ - DNS record management
42
+ - Domain contact information
43
+ - Domain information retrieval
44
+
45
+ Other Namecheap API features (like SSL certificates, email services, etc.) may be implemented in the future, but they are not currently a priority.
46
+
47
+ ## Project Goals
48
+
49
+ - Provide a simple, intuitive Python interface to the Namecheap API
50
+ - Support domain management endpoints in the Namecheap API
51
+ - Handle authentication and request formatting automatically
52
+ - Return responses in Pythonic data structures (not raw XML)
53
+ - Comprehensive error handling with detailed error messages
54
+ - Well-documented with examples for common operations
55
+
56
+ ## Requirements
57
+
58
+ - Python 3.7+
59
+ - A Namecheap account with API access enabled
60
+ - API key from your Namecheap account
61
+ - Whitelisted IP address(es) that will make API requests
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ pip install namecheap-python
67
+ ```
68
+
69
+ ### For Developers
70
+
71
+ This project uses Poetry for dependency management and packaging:
72
+
73
+ ```bash
74
+ # Install poetry
75
+ curl -sSL https://install.python-poetry.org | python3 -
76
+
77
+ # Setup development environment
78
+ poetry install
79
+
80
+ # Run tests
81
+ poetry run pytest
82
+
83
+ # Build package
84
+ poetry build
85
+
86
+ # Publish to PyPI
87
+ poetry publish
88
+ ```
89
+
90
+ ## Authentication
91
+
92
+ To use the Namecheap API, you need:
93
+
94
+ 1. A Namecheap account
95
+ 2. API access enabled on your account (do this at https://ap.www.namecheap.com/settings/tools/apiaccess/)
96
+ 3. An API key generated from your Namecheap dashboard
97
+ 4. Your client IP address(es) whitelisted
98
+
99
+ The Namecheap API uses the following authentication parameters:
100
+ - `ApiUser`: Your Namecheap username
101
+ - `ApiKey`: Your API key
102
+ - `UserName`: Your Namecheap username (typically the same as ApiUser)
103
+ - `ClientIp`: The whitelisted IP address making the request
104
+
105
+ ## Usage
106
+
107
+ ### Basic Setup
108
+
109
+ ```python
110
+ from namecheap import NamecheapClient, NamecheapException
111
+
112
+ # Method 1: Initialize with explicit credentials
113
+ client = NamecheapClient(
114
+ api_user="your_username",
115
+ api_key="your_api_key",
116
+ username="your_username",
117
+ client_ip="your_whitelisted_ip",
118
+ sandbox=True, # Use False for production
119
+ debug=False # Set to True for debugging request and response details
120
+ )
121
+
122
+ # Method 2: Initialize using environment variables (recommended)
123
+ # Set these in your environment or .env file:
124
+ # NAMECHEAP_API_USER=your_username
125
+ # NAMECHEAP_API_KEY=your_api_key
126
+ # NAMECHEAP_USERNAME=your_username
127
+ # NAMECHEAP_CLIENT_IP=your_whitelisted_ip
128
+ # NAMECHEAP_USE_SANDBOX=True
129
+
130
+ client = NamecheapClient() # Automatically loads credentials from environment
131
+ ```
132
+
133
+ ### Check Domain Availability
134
+
135
+ ```python
136
+ try:
137
+ # Check multiple domains at once (up to 50)
138
+ domains_to_check = ["example.com", "example.net", "example.org"]
139
+ result = client.domains_check(domains_to_check)
140
+
141
+ # Process results
142
+ for domain in result.get("DomainCheckResult", []):
143
+ print(f"{domain['Domain']}: {'Available' if domain['Available'] else 'Not available'}")
144
+ if domain['IsPremiumName']:
145
+ print(f" Premium Domain - Price: {domain['PremiumRegistrationPrice']}")
146
+ except NamecheapException as e:
147
+ print(f"API Error: {e}")
148
+ ```
149
+
150
+ ### Example Output
151
+
152
+ Running the check_domain.py example produces output like the following:
153
+
154
+ ```
155
+ Checking availability for: example.com, something123unique.com
156
+
157
+ Results:
158
+ ------------------------------------------------------------
159
+ Domain Available Premium Price
160
+ ------------------------------------------------------------
161
+ example.com No No N/A
162
+ something123unique.com Yes No N/A
163
+ ```
164
+
165
+ ### List Your Domains
166
+
167
+ ```python
168
+ try:
169
+ # Get list of domains in your account
170
+ result = client.domains_get_list(
171
+ page=1,
172
+ page_size=20,
173
+ sort_by="NAME",
174
+ list_type="ALL"
175
+ )
176
+
177
+ # Process domain list
178
+ domains = result.get("DomainGetListResult", {}).get("Domain", [])
179
+
180
+ for domain in domains:
181
+ print(f"Domain: {domain.get('Name')}")
182
+ print(f" Expires: {domain.get('Expires')}")
183
+ except NamecheapException as e:
184
+ print(f"API Error: {e}")
185
+ ```
186
+
187
+ ### Register a Domain
188
+
189
+ ```python
190
+ try:
191
+ # Contact information required for domain registration
192
+ registrant_info = {
193
+ "FirstName": "John",
194
+ "LastName": "Doe",
195
+ "Address1": "123 Main St",
196
+ "City": "Anytown",
197
+ "StateProvince": "CA",
198
+ "PostalCode": "12345",
199
+ "Country": "US",
200
+ "Phone": "+1.1234567890",
201
+ "EmailAddress": "john@example.com"
202
+ }
203
+
204
+ # Register a new domain
205
+ result = client.domains_create(
206
+ domain_name="example.com",
207
+ years=1,
208
+ registrant_info=registrant_info,
209
+ nameservers=["dns1.namecheaphosting.com", "dns2.namecheaphosting.com"],
210
+ add_free_whois_guard=True,
211
+ wg_enabled=True
212
+ )
213
+
214
+ # Process result
215
+ domain_id = result.get("DomainCreateResult", {}).get("Domain", {}).get("ID")
216
+ print(f"Domain registered with ID: {domain_id}")
217
+ except NamecheapException as e:
218
+ print(f"API Error: {e}")
219
+ ```
220
+
221
+ ### Manage DNS Records
222
+
223
+ ```python
224
+ try:
225
+ # Get existing DNS records
226
+ result = client.domains_dns_get_hosts("example.com")
227
+
228
+ # The fields below use the more intuitive format, but the API will accept either format:
229
+ # - Name/HostName (both work)
230
+ # - Type/RecordType (both work)
231
+ # - Value/Address (both work)
232
+ # - Priority/MXPref (for MX records, both work)
233
+
234
+ # Add new DNS records
235
+ dns_records = [
236
+ {
237
+ "Name": "@",
238
+ "Type": "A",
239
+ "Value": "192.0.2.1",
240
+ "TTL": 1800 # Can be int or string
241
+ },
242
+ {
243
+ "Name": "www",
244
+ "Type": "CNAME",
245
+ "Value": "@",
246
+ "TTL": 1800
247
+ },
248
+ {
249
+ "Name": "mail",
250
+ "Type": "MX",
251
+ "Value": "mail.example.com",
252
+ "Priority": 10, # MX priority
253
+ "TTL": 1800
254
+ }
255
+ ]
256
+
257
+ # Set the DNS records
258
+ result = client.domains_dns_set_hosts(
259
+ domain_name="example.com",
260
+ hosts=dns_records
261
+ )
262
+
263
+ print("DNS records updated successfully")
264
+ except NamecheapException as e:
265
+ print(f"API Error: {e}")
266
+ ```
267
+
268
+ ### Using the DNS Tool
269
+
270
+ The package includes a handy DNS management tool that you can use to manage your DNS records from the command line.
271
+
272
+ ```bash
273
+ # List all DNS records for a domain
274
+ python examples/dns_tool.py list example.com
275
+
276
+ # Add a DNS record
277
+ python examples/dns_tool.py add example.com --name blog --type A --value 192.0.2.1 --ttl 1800
278
+
279
+ # Delete a DNS record
280
+ python examples/dns_tool.py delete example.com --name blog --type A
281
+
282
+ # Import DNS records from a JSON file
283
+ python examples/dns_tool.py import example.com dns_records.json
284
+
285
+ # Export DNS records to a JSON file
286
+ python examples/dns_tool.py export example.com dns_records.json
287
+ ```
288
+
289
+ ## Sandbox Environment
290
+
291
+ Namecheap provides a sandbox environment for testing. To use it, set `sandbox=True` when initializing the client.
292
+
293
+ ## Rate Limits
294
+
295
+ Namecheap API has the following rate limits:
296
+ - 20 requests per minute
297
+ - 700 requests per hour
298
+ - 8000 requests per day
299
+
300
+ ## Supported Endpoints
301
+
302
+ The SDK currently supports the following Namecheap API endpoints:
303
+
304
+ ### Domains
305
+ - `domains_check` - Check domain availability
306
+ - `domains_get_list` - Get list of domains in your account
307
+ - `domains_get_contacts` - Get contact information for a domain
308
+ - `domains_create` - Register a new domain
309
+ - `domains_renew` - Renew a domain
310
+ - `domains_get_info` - Get detailed information about a domain
311
+ - `domains_get_tld_list` - Get list of available TLDs
312
+
313
+ ### DNS
314
+ - `domains_dns_set_custom` - Set custom nameservers for a domain
315
+ - `domains_dns_set_default` - Set default nameservers for a domain
316
+ - `domains_dns_get_hosts` - Get DNS host records for a domain
317
+ - `domains_dns_set_hosts` - Set DNS host records for a domain
318
+
319
+ Additional endpoints from the Namecheap API may be added in future releases based on user needs and contributions.
320
+
321
+ ## Error Handling
322
+
323
+ The SDK includes a `NamecheapException` class that provides detailed error information from the API:
324
+
325
+ ```python
326
+ try:
327
+ result = client.domains_check(["example.com"])
328
+ except NamecheapException as e:
329
+ print(f"Error code: {e.code}")
330
+ print(f"Error message: {e.message}")
331
+ ```
332
+
333
+ ## Contributing
334
+
335
+ Contributions are welcome! Please feel free to submit a Pull Request.
336
+
337
+ ## License
338
+
339
+ This project is licensed under the MIT License - see the LICENSE file for details.
340
+
341
+ ## Disclaimer
342
+
343
+ All this code was produced in a single sitting vibe coding with `claude code` for 2 hours and ~$25.
344
+
345
+ Excuse the occasional AI slop, if you spot it let me know.
346
+
@@ -0,0 +1,316 @@
1
+ # Namecheap Python SDK
2
+
3
+ A Python wrapper for the Namecheap API that allows developers to interact programmatically with Namecheap's domain registration and management services.
4
+
5
+ I needed an MCP, so I needed an API, I checked and the previous python API SDK for Namecheap was abandoned, so I went ahead and did this one.
6
+
7
+ ## Project Focus
8
+
9
+ This SDK currently focuses on domain management functionality of the Namecheap API, including:
10
+ - Domain availability checking
11
+ - Domain registration and renewal
12
+ - DNS record management
13
+ - Domain contact information
14
+ - Domain information retrieval
15
+
16
+ Other Namecheap API features (like SSL certificates, email services, etc.) may be implemented in the future, but they are not currently a priority.
17
+
18
+ ## Project Goals
19
+
20
+ - Provide a simple, intuitive Python interface to the Namecheap API
21
+ - Support domain management endpoints in the Namecheap API
22
+ - Handle authentication and request formatting automatically
23
+ - Return responses in Pythonic data structures (not raw XML)
24
+ - Comprehensive error handling with detailed error messages
25
+ - Well-documented with examples for common operations
26
+
27
+ ## Requirements
28
+
29
+ - Python 3.7+
30
+ - A Namecheap account with API access enabled
31
+ - API key from your Namecheap account
32
+ - Whitelisted IP address(es) that will make API requests
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install namecheap-python
38
+ ```
39
+
40
+ ### For Developers
41
+
42
+ This project uses Poetry for dependency management and packaging:
43
+
44
+ ```bash
45
+ # Install poetry
46
+ curl -sSL https://install.python-poetry.org | python3 -
47
+
48
+ # Setup development environment
49
+ poetry install
50
+
51
+ # Run tests
52
+ poetry run pytest
53
+
54
+ # Build package
55
+ poetry build
56
+
57
+ # Publish to PyPI
58
+ poetry publish
59
+ ```
60
+
61
+ ## Authentication
62
+
63
+ To use the Namecheap API, you need:
64
+
65
+ 1. A Namecheap account
66
+ 2. API access enabled on your account (do this at https://ap.www.namecheap.com/settings/tools/apiaccess/)
67
+ 3. An API key generated from your Namecheap dashboard
68
+ 4. Your client IP address(es) whitelisted
69
+
70
+ The Namecheap API uses the following authentication parameters:
71
+ - `ApiUser`: Your Namecheap username
72
+ - `ApiKey`: Your API key
73
+ - `UserName`: Your Namecheap username (typically the same as ApiUser)
74
+ - `ClientIp`: The whitelisted IP address making the request
75
+
76
+ ## Usage
77
+
78
+ ### Basic Setup
79
+
80
+ ```python
81
+ from namecheap import NamecheapClient, NamecheapException
82
+
83
+ # Method 1: Initialize with explicit credentials
84
+ client = NamecheapClient(
85
+ api_user="your_username",
86
+ api_key="your_api_key",
87
+ username="your_username",
88
+ client_ip="your_whitelisted_ip",
89
+ sandbox=True, # Use False for production
90
+ debug=False # Set to True for debugging request and response details
91
+ )
92
+
93
+ # Method 2: Initialize using environment variables (recommended)
94
+ # Set these in your environment or .env file:
95
+ # NAMECHEAP_API_USER=your_username
96
+ # NAMECHEAP_API_KEY=your_api_key
97
+ # NAMECHEAP_USERNAME=your_username
98
+ # NAMECHEAP_CLIENT_IP=your_whitelisted_ip
99
+ # NAMECHEAP_USE_SANDBOX=True
100
+
101
+ client = NamecheapClient() # Automatically loads credentials from environment
102
+ ```
103
+
104
+ ### Check Domain Availability
105
+
106
+ ```python
107
+ try:
108
+ # Check multiple domains at once (up to 50)
109
+ domains_to_check = ["example.com", "example.net", "example.org"]
110
+ result = client.domains_check(domains_to_check)
111
+
112
+ # Process results
113
+ for domain in result.get("DomainCheckResult", []):
114
+ print(f"{domain['Domain']}: {'Available' if domain['Available'] else 'Not available'}")
115
+ if domain['IsPremiumName']:
116
+ print(f" Premium Domain - Price: {domain['PremiumRegistrationPrice']}")
117
+ except NamecheapException as e:
118
+ print(f"API Error: {e}")
119
+ ```
120
+
121
+ ### Example Output
122
+
123
+ Running the check_domain.py example produces output like the following:
124
+
125
+ ```
126
+ Checking availability for: example.com, something123unique.com
127
+
128
+ Results:
129
+ ------------------------------------------------------------
130
+ Domain Available Premium Price
131
+ ------------------------------------------------------------
132
+ example.com No No N/A
133
+ something123unique.com Yes No N/A
134
+ ```
135
+
136
+ ### List Your Domains
137
+
138
+ ```python
139
+ try:
140
+ # Get list of domains in your account
141
+ result = client.domains_get_list(
142
+ page=1,
143
+ page_size=20,
144
+ sort_by="NAME",
145
+ list_type="ALL"
146
+ )
147
+
148
+ # Process domain list
149
+ domains = result.get("DomainGetListResult", {}).get("Domain", [])
150
+
151
+ for domain in domains:
152
+ print(f"Domain: {domain.get('Name')}")
153
+ print(f" Expires: {domain.get('Expires')}")
154
+ except NamecheapException as e:
155
+ print(f"API Error: {e}")
156
+ ```
157
+
158
+ ### Register a Domain
159
+
160
+ ```python
161
+ try:
162
+ # Contact information required for domain registration
163
+ registrant_info = {
164
+ "FirstName": "John",
165
+ "LastName": "Doe",
166
+ "Address1": "123 Main St",
167
+ "City": "Anytown",
168
+ "StateProvince": "CA",
169
+ "PostalCode": "12345",
170
+ "Country": "US",
171
+ "Phone": "+1.1234567890",
172
+ "EmailAddress": "john@example.com"
173
+ }
174
+
175
+ # Register a new domain
176
+ result = client.domains_create(
177
+ domain_name="example.com",
178
+ years=1,
179
+ registrant_info=registrant_info,
180
+ nameservers=["dns1.namecheaphosting.com", "dns2.namecheaphosting.com"],
181
+ add_free_whois_guard=True,
182
+ wg_enabled=True
183
+ )
184
+
185
+ # Process result
186
+ domain_id = result.get("DomainCreateResult", {}).get("Domain", {}).get("ID")
187
+ print(f"Domain registered with ID: {domain_id}")
188
+ except NamecheapException as e:
189
+ print(f"API Error: {e}")
190
+ ```
191
+
192
+ ### Manage DNS Records
193
+
194
+ ```python
195
+ try:
196
+ # Get existing DNS records
197
+ result = client.domains_dns_get_hosts("example.com")
198
+
199
+ # The fields below use the more intuitive format, but the API will accept either format:
200
+ # - Name/HostName (both work)
201
+ # - Type/RecordType (both work)
202
+ # - Value/Address (both work)
203
+ # - Priority/MXPref (for MX records, both work)
204
+
205
+ # Add new DNS records
206
+ dns_records = [
207
+ {
208
+ "Name": "@",
209
+ "Type": "A",
210
+ "Value": "192.0.2.1",
211
+ "TTL": 1800 # Can be int or string
212
+ },
213
+ {
214
+ "Name": "www",
215
+ "Type": "CNAME",
216
+ "Value": "@",
217
+ "TTL": 1800
218
+ },
219
+ {
220
+ "Name": "mail",
221
+ "Type": "MX",
222
+ "Value": "mail.example.com",
223
+ "Priority": 10, # MX priority
224
+ "TTL": 1800
225
+ }
226
+ ]
227
+
228
+ # Set the DNS records
229
+ result = client.domains_dns_set_hosts(
230
+ domain_name="example.com",
231
+ hosts=dns_records
232
+ )
233
+
234
+ print("DNS records updated successfully")
235
+ except NamecheapException as e:
236
+ print(f"API Error: {e}")
237
+ ```
238
+
239
+ ### Using the DNS Tool
240
+
241
+ The package includes a handy DNS management tool that you can use to manage your DNS records from the command line.
242
+
243
+ ```bash
244
+ # List all DNS records for a domain
245
+ python examples/dns_tool.py list example.com
246
+
247
+ # Add a DNS record
248
+ python examples/dns_tool.py add example.com --name blog --type A --value 192.0.2.1 --ttl 1800
249
+
250
+ # Delete a DNS record
251
+ python examples/dns_tool.py delete example.com --name blog --type A
252
+
253
+ # Import DNS records from a JSON file
254
+ python examples/dns_tool.py import example.com dns_records.json
255
+
256
+ # Export DNS records to a JSON file
257
+ python examples/dns_tool.py export example.com dns_records.json
258
+ ```
259
+
260
+ ## Sandbox Environment
261
+
262
+ Namecheap provides a sandbox environment for testing. To use it, set `sandbox=True` when initializing the client.
263
+
264
+ ## Rate Limits
265
+
266
+ Namecheap API has the following rate limits:
267
+ - 20 requests per minute
268
+ - 700 requests per hour
269
+ - 8000 requests per day
270
+
271
+ ## Supported Endpoints
272
+
273
+ The SDK currently supports the following Namecheap API endpoints:
274
+
275
+ ### Domains
276
+ - `domains_check` - Check domain availability
277
+ - `domains_get_list` - Get list of domains in your account
278
+ - `domains_get_contacts` - Get contact information for a domain
279
+ - `domains_create` - Register a new domain
280
+ - `domains_renew` - Renew a domain
281
+ - `domains_get_info` - Get detailed information about a domain
282
+ - `domains_get_tld_list` - Get list of available TLDs
283
+
284
+ ### DNS
285
+ - `domains_dns_set_custom` - Set custom nameservers for a domain
286
+ - `domains_dns_set_default` - Set default nameservers for a domain
287
+ - `domains_dns_get_hosts` - Get DNS host records for a domain
288
+ - `domains_dns_set_hosts` - Set DNS host records for a domain
289
+
290
+ Additional endpoints from the Namecheap API may be added in future releases based on user needs and contributions.
291
+
292
+ ## Error Handling
293
+
294
+ The SDK includes a `NamecheapException` class that provides detailed error information from the API:
295
+
296
+ ```python
297
+ try:
298
+ result = client.domains_check(["example.com"])
299
+ except NamecheapException as e:
300
+ print(f"Error code: {e.code}")
301
+ print(f"Error message: {e.message}")
302
+ ```
303
+
304
+ ## Contributing
305
+
306
+ Contributions are welcome! Please feel free to submit a Pull Request.
307
+
308
+ ## License
309
+
310
+ This project is licensed under the MIT License - see the LICENSE file for details.
311
+
312
+ ## Disclaimer
313
+
314
+ All this code was produced in a single sitting vibe coding with `claude code` for 2 hours and ~$25.
315
+
316
+ Excuse the occasional AI slop, if you spot it let me know.