replylayer 0.14.0__py3-none-any.whl
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.
- replylayer/__init__.py +143 -0
- replylayer/_client.py +128 -0
- replylayer/_http.py +326 -0
- replylayer/_pagination.py +34 -0
- replylayer/errors.py +152 -0
- replylayer/py.typed +0 -0
- replylayer/resources/__init__.py +0 -0
- replylayer/resources/account.py +36 -0
- replylayer/resources/api_keys.py +59 -0
- replylayer/resources/attachments.py +115 -0
- replylayer/resources/domains.py +79 -0
- replylayer/resources/drafts.py +342 -0
- replylayer/resources/health.py +21 -0
- replylayer/resources/inbound_blocklist.py +93 -0
- replylayer/resources/legal_holds.py +107 -0
- replylayer/resources/mailboxes.py +768 -0
- replylayer/resources/messages.py +425 -0
- replylayer/resources/recipients.py +59 -0
- replylayer/resources/suppressions.py +84 -0
- replylayer/resources/threads.py +117 -0
- replylayer/resources/webhooks.py +175 -0
- replylayer/types.py +1578 -0
- replylayer-0.14.0.dist-info/METADATA +502 -0
- replylayer-0.14.0.dist-info/RECORD +25 -0
- replylayer-0.14.0.dist-info/WHEEL +4 -0
replylayer/errors.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReplyLayerError(Exception):
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
status_code: int,
|
|
10
|
+
code: str,
|
|
11
|
+
message: str,
|
|
12
|
+
details: dict[str, Any] | None = None,
|
|
13
|
+
) -> None:
|
|
14
|
+
super().__init__(message)
|
|
15
|
+
self.status_code = status_code
|
|
16
|
+
self.code = code
|
|
17
|
+
self.details = details
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AuthenticationError(ReplyLayerError):
|
|
21
|
+
def __init__(self, code: str, message: str, details: dict[str, Any] | None = None) -> None:
|
|
22
|
+
super().__init__(401, code, message, details)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ForbiddenError(ReplyLayerError):
|
|
26
|
+
def __init__(self, code: str, message: str, details: dict[str, Any] | None = None) -> None:
|
|
27
|
+
super().__init__(403, code, message, details)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class NotFoundError(ReplyLayerError):
|
|
31
|
+
def __init__(self, code: str, message: str, details: dict[str, Any] | None = None) -> None:
|
|
32
|
+
super().__init__(404, code, message, details)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ValidationError(ReplyLayerError):
|
|
36
|
+
def __init__(self, status_code: int, code: str, message: str, details: dict[str, Any] | None = None) -> None:
|
|
37
|
+
super().__init__(status_code, code, message, details)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RateLimitError(ReplyLayerError):
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
code: str,
|
|
44
|
+
message: str,
|
|
45
|
+
headers: dict[str, str],
|
|
46
|
+
details: dict[str, Any] | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
super().__init__(429, code, message, details)
|
|
49
|
+
ra = headers.get("retry-after")
|
|
50
|
+
self.retry_after: int | None = int(ra) if ra and ra.isdigit() else None
|
|
51
|
+
lim = headers.get("x-ratelimit-limit")
|
|
52
|
+
self.limit: int | None = int(lim) if lim and lim.isdigit() else None
|
|
53
|
+
rem = headers.get("x-ratelimit-remaining")
|
|
54
|
+
self.remaining: int | None = int(rem) if rem and rem.isdigit() else None
|
|
55
|
+
self.reset: str | None = headers.get("x-ratelimit-reset")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class WebhookSignatureError(ReplyLayerError):
|
|
59
|
+
def __init__(self, message: str) -> None:
|
|
60
|
+
super().__init__(0, "WEBHOOK_SIGNATURE_ERROR", message)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Migration 040 — scheduled-send error surface. Raised when scheduled-send
|
|
64
|
+
# routes reject a request (invalid TZ / too-soon / too-far / quota breach /
|
|
65
|
+
# Idempotency-Key without send_at). Subclass of ReplyLayerError so generic
|
|
66
|
+
# catches still work; typed .reason_code narrows for per-reason handling.
|
|
67
|
+
#
|
|
68
|
+
# NOT raised for runtime dispatch failures — those surface as
|
|
69
|
+
# message.dispatch_failed webhook events, not SDK exceptions.
|
|
70
|
+
_SCHEDULING_REASON_CODES: frozenset[str] = frozenset({
|
|
71
|
+
"TIMEZONE_REQUIRED",
|
|
72
|
+
"SEND_AT_TOO_SOON",
|
|
73
|
+
"SEND_AT_TOO_FAR",
|
|
74
|
+
"SCHEDULED_SEND_QUOTA_EXCEEDED",
|
|
75
|
+
"IDEMPOTENCY_KEY_REQUIRES_SEND_AT",
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class SchedulingError(ReplyLayerError):
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
status_code: int,
|
|
83
|
+
code: str,
|
|
84
|
+
message: str,
|
|
85
|
+
details: dict[str, Any] | None = None,
|
|
86
|
+
) -> None:
|
|
87
|
+
super().__init__(status_code, code, message, details)
|
|
88
|
+
self.reason_code: str = code
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class TimezoneRequiredError(SchedulingError):
|
|
92
|
+
"""
|
|
93
|
+
Raised CLIENT-SIDE (before the HTTP call) when a caller passes a
|
|
94
|
+
``datetime`` without tzinfo on ``send_at``. The TS SDK equivalent is a
|
|
95
|
+
400 TIMEZONE_REQUIRED from the server; in Python we fail fast because
|
|
96
|
+
``datetime.isoformat()`` on a naive datetime produces a naive ISO
|
|
97
|
+
string that the server would then reject anyway — better to raise at
|
|
98
|
+
the call site where the stack trace points at the bug.
|
|
99
|
+
|
|
100
|
+
The ``status_code`` is set to 400 for API parity, but no HTTP call was
|
|
101
|
+
actually made.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(self, message: str | None = None) -> None:
|
|
105
|
+
super().__init__(
|
|
106
|
+
400,
|
|
107
|
+
"TIMEZONE_REQUIRED",
|
|
108
|
+
message or (
|
|
109
|
+
"send_at must be timezone-aware. Use datetime.now(timezone.utc) "
|
|
110
|
+
"or attach tzinfo before passing. An ISO string with offset or "
|
|
111
|
+
"'Z' is also accepted."
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def error_from_response(
|
|
117
|
+
status: int,
|
|
118
|
+
body: dict[str, Any],
|
|
119
|
+
headers: dict[str, str],
|
|
120
|
+
) -> ReplyLayerError:
|
|
121
|
+
message = body.get("error", f"HTTP {status}")
|
|
122
|
+
# Coerce a non-string ``code`` to a string. ``body["code"]`` is typed as a
|
|
123
|
+
# string but the wire carries whatever JSON parsed — an edge gateway (e.g.
|
|
124
|
+
# a proxy on a long-poll 502) can put a NUMERIC code on the body, surprising
|
|
125
|
+
# any caller doing ``isinstance(err.code, str)``. ``is not None`` preserves a
|
|
126
|
+
# legitimate ``0`` (-> "0"); the ``or`` catches None/empty -> HTTP_<status>.
|
|
127
|
+
# Mirrors the CLI client + the TS SDK.
|
|
128
|
+
raw_code = body.get("code")
|
|
129
|
+
code = (str(raw_code) if raw_code is not None else "") or f"HTTP_{status}"
|
|
130
|
+
details = body.get("details")
|
|
131
|
+
|
|
132
|
+
# Migration 040 — scheduling errors are a narrow subclass of
|
|
133
|
+
# status-generic errors. Map BEFORE the status switch so a 429 with
|
|
134
|
+
# SCHEDULED_SEND_QUOTA_EXCEEDED becomes a SchedulingError, not a
|
|
135
|
+
# RateLimitError (consumers filtering on .retry_after wouldn't expect
|
|
136
|
+
# quota-type 429s anyway). 400s likewise become SchedulingError
|
|
137
|
+
# rather than ValidationError so `isinstance(err, SchedulingError)`
|
|
138
|
+
# works uniformly across statuses.
|
|
139
|
+
if code in _SCHEDULING_REASON_CODES:
|
|
140
|
+
return SchedulingError(status, code, message, details)
|
|
141
|
+
|
|
142
|
+
if status == 401:
|
|
143
|
+
return AuthenticationError(code, message, details)
|
|
144
|
+
if status == 403:
|
|
145
|
+
return ForbiddenError(code, message, details)
|
|
146
|
+
if status == 404:
|
|
147
|
+
return NotFoundError(code, message, details)
|
|
148
|
+
if status == 429:
|
|
149
|
+
return RateLimitError(code, message, headers, details)
|
|
150
|
+
if status in (400, 422):
|
|
151
|
+
return ValidationError(status, code, message, details)
|
|
152
|
+
return ReplyLayerError(status, code, message, details)
|
replylayer/py.typed
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .._http import AsyncHttpClient, SyncHttpClient
|
|
6
|
+
from ..types import QuotaResponse, UsageResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SyncAccount:
|
|
10
|
+
def __init__(self, http: SyncHttpClient) -> None:
|
|
11
|
+
self._http = http
|
|
12
|
+
|
|
13
|
+
def get_usage(self) -> UsageResponse:
|
|
14
|
+
return self._http.request("GET", "/v1/accounts/usage")
|
|
15
|
+
|
|
16
|
+
def get_quota(self) -> QuotaResponse:
|
|
17
|
+
return self._http.request("GET", "/v1/accounts/quota")
|
|
18
|
+
|
|
19
|
+
def export(self) -> dict[str, Any]:
|
|
20
|
+
"""GDPR Art. 20 data portability export — the full account-data object."""
|
|
21
|
+
return self._http.request("GET", "/v1/accounts/export")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AsyncAccount:
|
|
25
|
+
def __init__(self, http: AsyncHttpClient) -> None:
|
|
26
|
+
self._http = http
|
|
27
|
+
|
|
28
|
+
async def get_usage(self) -> UsageResponse:
|
|
29
|
+
return await self._http.request("GET", "/v1/accounts/usage")
|
|
30
|
+
|
|
31
|
+
async def get_quota(self) -> QuotaResponse:
|
|
32
|
+
return await self._http.request("GET", "/v1/accounts/quota")
|
|
33
|
+
|
|
34
|
+
async def export(self) -> dict[str, Any]:
|
|
35
|
+
"""GDPR Art. 20 data portability export — the full account-data object."""
|
|
36
|
+
return await self._http.request("GET", "/v1/accounts/export")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .._http import AsyncHttpClient, SyncHttpClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SyncApiKeys:
|
|
9
|
+
def __init__(self, http: SyncHttpClient) -> None:
|
|
10
|
+
self._http = http
|
|
11
|
+
|
|
12
|
+
def create(self, *, role: str, label: str | None = None, mailbox_ids: list[str] | None = None) -> dict[str, Any]:
|
|
13
|
+
payload: dict[str, Any] = {"role": role}
|
|
14
|
+
if label is not None:
|
|
15
|
+
payload["label"] = label
|
|
16
|
+
if mailbox_ids is not None:
|
|
17
|
+
payload["mailbox_ids"] = mailbox_ids
|
|
18
|
+
return self._http.request("POST", "/v1/accounts/api-keys", body=payload)
|
|
19
|
+
|
|
20
|
+
def list(self, *, include_revoked: bool = False) -> dict[str, Any]:
|
|
21
|
+
# D4 / RL-UAT-019 — active-only by default; include_revoked=True returns
|
|
22
|
+
# revoked keys with revoked_at/revoked_by metadata.
|
|
23
|
+
query = {"include_revoked": "true"} if include_revoked else None
|
|
24
|
+
return self._http.request("GET", "/v1/accounts/api-keys", query=query)
|
|
25
|
+
|
|
26
|
+
def revoke(self, id: str) -> dict[str, Any]:
|
|
27
|
+
return self._http.request("DELETE", f"/v1/accounts/api-keys/{id}")
|
|
28
|
+
|
|
29
|
+
def rotate(self) -> dict[str, Any]:
|
|
30
|
+
"""Rotate the calling API key. After this call, this SDK instance's key
|
|
31
|
+
is invalidated. Create a new ReplyLayer instance with the returned key."""
|
|
32
|
+
return self._http.request("POST", "/v1/accounts/api-keys/rotate")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AsyncApiKeys:
|
|
36
|
+
def __init__(self, http: AsyncHttpClient) -> None:
|
|
37
|
+
self._http = http
|
|
38
|
+
|
|
39
|
+
async def create(self, *, role: str, label: str | None = None, mailbox_ids: list[str] | None = None) -> dict[str, Any]:
|
|
40
|
+
payload: dict[str, Any] = {"role": role}
|
|
41
|
+
if label is not None:
|
|
42
|
+
payload["label"] = label
|
|
43
|
+
if mailbox_ids is not None:
|
|
44
|
+
payload["mailbox_ids"] = mailbox_ids
|
|
45
|
+
return await self._http.request("POST", "/v1/accounts/api-keys", body=payload)
|
|
46
|
+
|
|
47
|
+
async def list(self, *, include_revoked: bool = False) -> dict[str, Any]:
|
|
48
|
+
# D4 / RL-UAT-019 — active-only by default; include_revoked=True returns
|
|
49
|
+
# revoked keys with revoked_at/revoked_by metadata.
|
|
50
|
+
query = {"include_revoked": "true"} if include_revoked else None
|
|
51
|
+
return await self._http.request("GET", "/v1/accounts/api-keys", query=query)
|
|
52
|
+
|
|
53
|
+
async def revoke(self, id: str) -> dict[str, Any]:
|
|
54
|
+
return await self._http.request("DELETE", f"/v1/accounts/api-keys/{id}")
|
|
55
|
+
|
|
56
|
+
async def rotate(self) -> dict[str, Any]:
|
|
57
|
+
"""Rotate the calling API key. After this call, this SDK instance's key
|
|
58
|
+
is invalidated. Create a new AsyncReplyLayer instance with the returned key."""
|
|
59
|
+
return await self._http.request("POST", "/v1/accounts/api-keys/rotate")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import IO, Any, cast
|
|
4
|
+
|
|
5
|
+
from .._http import AsyncHttpClient, SyncHttpClient
|
|
6
|
+
from ..types import (
|
|
7
|
+
AttachmentPreviewResponse,
|
|
8
|
+
GetUploadAttachmentResponse,
|
|
9
|
+
UploadAttachmentResponse,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _upload_kwargs(
|
|
14
|
+
*,
|
|
15
|
+
mailbox_id: str,
|
|
16
|
+
file: bytes | IO[bytes],
|
|
17
|
+
filename: str,
|
|
18
|
+
content_type: str | None,
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
|
+
"""Build the httpx files=/data= kwargs for POST /v1/attachments.
|
|
21
|
+
|
|
22
|
+
The file part is a (filename, content[, content_type]) tuple; the
|
|
23
|
+
mailbox_id is a plain multipart text field. content_type is advisory — the
|
|
24
|
+
server re-sniffs the bytes and decides the trusted family regardless.
|
|
25
|
+
"""
|
|
26
|
+
file_part: tuple[Any, ...] = (
|
|
27
|
+
(filename, file, content_type) if content_type else (filename, file)
|
|
28
|
+
)
|
|
29
|
+
return {"files": {"file": file_part}, "data": {"mailbox_id": mailbox_id}}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SyncAttachments:
|
|
33
|
+
def __init__(self, http: SyncHttpClient) -> None:
|
|
34
|
+
self._http = http
|
|
35
|
+
|
|
36
|
+
def get_download_url(self, message_id: str, index: int) -> dict[str, Any]:
|
|
37
|
+
return self._http.request("GET", f"/v1/messages/{message_id}/attachments/{index}")
|
|
38
|
+
|
|
39
|
+
def get_preview(self, message_id: str, index: int) -> AttachmentPreviewResponse:
|
|
40
|
+
return cast(
|
|
41
|
+
AttachmentPreviewResponse,
|
|
42
|
+
self._http.request("GET", f"/v1/messages/{message_id}/attachments/{index}/preview"),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def upload(
|
|
46
|
+
self,
|
|
47
|
+
*,
|
|
48
|
+
mailbox_id: str,
|
|
49
|
+
file: bytes | IO[bytes],
|
|
50
|
+
filename: str,
|
|
51
|
+
content_type: str | None = None,
|
|
52
|
+
) -> UploadAttachmentResponse:
|
|
53
|
+
"""Stage an outbound attachment (phase 1). Returns an opaque handle;
|
|
54
|
+
pass ``handle["id"]`` in a send/reply/draft ``attachment_ids`` list. The
|
|
55
|
+
mailbox must have outbound attachments enabled (Pro+). The returned
|
|
56
|
+
``content_scan_status`` is ``"pending"`` — poll :meth:`get_upload` until
|
|
57
|
+
terminal before referencing the handle, or the send fails with
|
|
58
|
+
``ATTACHMENT_SCAN_PENDING``.
|
|
59
|
+
"""
|
|
60
|
+
kwargs = _upload_kwargs(
|
|
61
|
+
mailbox_id=mailbox_id, file=file, filename=filename, content_type=content_type
|
|
62
|
+
)
|
|
63
|
+
return cast(UploadAttachmentResponse, self._http.request("POST", "/v1/attachments", **kwargs))
|
|
64
|
+
|
|
65
|
+
def get_upload(self, attachment_id: str) -> GetUploadAttachmentResponse:
|
|
66
|
+
"""Poll a staged-attachment handle for its content-scan status (or
|
|
67
|
+
consumed state)."""
|
|
68
|
+
return cast(
|
|
69
|
+
GetUploadAttachmentResponse,
|
|
70
|
+
self._http.request("GET", f"/v1/attachments/{attachment_id}"),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def delete_upload(self, attachment_id: str) -> None:
|
|
74
|
+
"""Delete an un-consumed staged-attachment handle. A consumed handle → 409."""
|
|
75
|
+
self._http.request("DELETE", f"/v1/attachments/{attachment_id}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AsyncAttachments:
|
|
79
|
+
def __init__(self, http: AsyncHttpClient) -> None:
|
|
80
|
+
self._http = http
|
|
81
|
+
|
|
82
|
+
async def get_download_url(self, message_id: str, index: int) -> dict[str, Any]:
|
|
83
|
+
return await self._http.request("GET", f"/v1/messages/{message_id}/attachments/{index}")
|
|
84
|
+
|
|
85
|
+
async def get_preview(self, message_id: str, index: int) -> AttachmentPreviewResponse:
|
|
86
|
+
return cast(
|
|
87
|
+
AttachmentPreviewResponse,
|
|
88
|
+
await self._http.request("GET", f"/v1/messages/{message_id}/attachments/{index}/preview"),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def upload(
|
|
92
|
+
self,
|
|
93
|
+
*,
|
|
94
|
+
mailbox_id: str,
|
|
95
|
+
file: bytes | IO[bytes],
|
|
96
|
+
filename: str,
|
|
97
|
+
content_type: str | None = None,
|
|
98
|
+
) -> UploadAttachmentResponse:
|
|
99
|
+
"""Async variant of :meth:`SyncAttachments.upload`."""
|
|
100
|
+
kwargs = _upload_kwargs(
|
|
101
|
+
mailbox_id=mailbox_id, file=file, filename=filename, content_type=content_type
|
|
102
|
+
)
|
|
103
|
+
return cast(
|
|
104
|
+
UploadAttachmentResponse,
|
|
105
|
+
await self._http.request("POST", "/v1/attachments", **kwargs),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
async def get_upload(self, attachment_id: str) -> GetUploadAttachmentResponse:
|
|
109
|
+
return cast(
|
|
110
|
+
GetUploadAttachmentResponse,
|
|
111
|
+
await self._http.request("GET", f"/v1/attachments/{attachment_id}"),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
async def delete_upload(self, attachment_id: str) -> None:
|
|
115
|
+
await self._http.request("DELETE", f"/v1/attachments/{attachment_id}")
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .._http import AsyncHttpClient, SyncHttpClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SyncDomains:
|
|
9
|
+
def __init__(self, http: SyncHttpClient) -> None:
|
|
10
|
+
self._http = http
|
|
11
|
+
|
|
12
|
+
def create(self, **params: Any) -> dict[str, Any]:
|
|
13
|
+
return self._http.request("POST", "/v1/domains", body=params)
|
|
14
|
+
|
|
15
|
+
def list(self) -> dict[str, Any]:
|
|
16
|
+
return self._http.request("GET", "/v1/domains")
|
|
17
|
+
|
|
18
|
+
def get(self, id: str) -> dict[str, Any]:
|
|
19
|
+
return self._http.request("GET", f"/v1/domains/{id}")
|
|
20
|
+
|
|
21
|
+
def verify(self, id: str) -> dict[str, Any]:
|
|
22
|
+
return self._http.request("POST", f"/v1/domains/{id}/verify")
|
|
23
|
+
|
|
24
|
+
def update_self_hosted_config(
|
|
25
|
+
self,
|
|
26
|
+
id: str,
|
|
27
|
+
**params: Any,
|
|
28
|
+
) -> dict[str, Any]:
|
|
29
|
+
return self._http.request(
|
|
30
|
+
"PATCH",
|
|
31
|
+
f"/v1/domains/{id}/self-hosted-config",
|
|
32
|
+
body=params,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def delete(self, id: str) -> dict[str, Any]:
|
|
36
|
+
return self._http.request("DELETE", f"/v1/domains/{id}")
|
|
37
|
+
|
|
38
|
+
def set_default(self, id: str) -> dict[str, Any]:
|
|
39
|
+
return self._http.request("PATCH", f"/v1/domains/{id}/set-default")
|
|
40
|
+
|
|
41
|
+
def recheck(self, id: str) -> dict[str, Any]:
|
|
42
|
+
return self._http.request("POST", f"/v1/domains/{id}/self-hosted-recheck")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AsyncDomains:
|
|
46
|
+
def __init__(self, http: AsyncHttpClient) -> None:
|
|
47
|
+
self._http = http
|
|
48
|
+
|
|
49
|
+
async def create(self, **params: Any) -> dict[str, Any]:
|
|
50
|
+
return await self._http.request("POST", "/v1/domains", body=params)
|
|
51
|
+
|
|
52
|
+
async def list(self) -> dict[str, Any]:
|
|
53
|
+
return await self._http.request("GET", "/v1/domains")
|
|
54
|
+
|
|
55
|
+
async def get(self, id: str) -> dict[str, Any]:
|
|
56
|
+
return await self._http.request("GET", f"/v1/domains/{id}")
|
|
57
|
+
|
|
58
|
+
async def verify(self, id: str) -> dict[str, Any]:
|
|
59
|
+
return await self._http.request("POST", f"/v1/domains/{id}/verify")
|
|
60
|
+
|
|
61
|
+
async def update_self_hosted_config(
|
|
62
|
+
self,
|
|
63
|
+
id: str,
|
|
64
|
+
**params: Any,
|
|
65
|
+
) -> dict[str, Any]:
|
|
66
|
+
return await self._http.request(
|
|
67
|
+
"PATCH",
|
|
68
|
+
f"/v1/domains/{id}/self-hosted-config",
|
|
69
|
+
body=params,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
async def delete(self, id: str) -> dict[str, Any]:
|
|
73
|
+
return await self._http.request("DELETE", f"/v1/domains/{id}")
|
|
74
|
+
|
|
75
|
+
async def set_default(self, id: str) -> dict[str, Any]:
|
|
76
|
+
return await self._http.request("PATCH", f"/v1/domains/{id}/set-default")
|
|
77
|
+
|
|
78
|
+
async def recheck(self, id: str) -> dict[str, Any]:
|
|
79
|
+
return await self._http.request("POST", f"/v1/domains/{id}/self-hosted-recheck")
|