universal-mcp-applications 0.1.1__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.
- universal_mcp/applications/ahrefs/README.md +51 -0
- universal_mcp/applications/ahrefs/__init__.py +1 -0
- universal_mcp/applications/ahrefs/app.py +2291 -0
- universal_mcp/applications/airtable/README.md +22 -0
- universal_mcp/applications/airtable/__init__.py +1 -0
- universal_mcp/applications/airtable/app.py +479 -0
- universal_mcp/applications/apollo/README.md +44 -0
- universal_mcp/applications/apollo/__init__.py +1 -0
- universal_mcp/applications/apollo/app.py +1847 -0
- universal_mcp/applications/asana/README.md +199 -0
- universal_mcp/applications/asana/__init__.py +1 -0
- universal_mcp/applications/asana/app.py +9509 -0
- universal_mcp/applications/aws-s3/README.md +0 -0
- universal_mcp/applications/aws-s3/__init__.py +1 -0
- universal_mcp/applications/aws-s3/app.py +552 -0
- universal_mcp/applications/bill/README.md +0 -0
- universal_mcp/applications/bill/__init__.py +1 -0
- universal_mcp/applications/bill/app.py +8705 -0
- universal_mcp/applications/box/README.md +307 -0
- universal_mcp/applications/box/__init__.py +1 -0
- universal_mcp/applications/box/app.py +15987 -0
- universal_mcp/applications/braze/README.md +106 -0
- universal_mcp/applications/braze/__init__.py +1 -0
- universal_mcp/applications/braze/app.py +4754 -0
- universal_mcp/applications/cal-com-v2/README.md +150 -0
- universal_mcp/applications/cal-com-v2/__init__.py +1 -0
- universal_mcp/applications/cal-com-v2/app.py +5541 -0
- universal_mcp/applications/calendly/README.md +53 -0
- universal_mcp/applications/calendly/__init__.py +1 -0
- universal_mcp/applications/calendly/app.py +1436 -0
- universal_mcp/applications/canva/README.md +43 -0
- universal_mcp/applications/canva/__init__.py +1 -0
- universal_mcp/applications/canva/app.py +941 -0
- universal_mcp/applications/clickup/README.md +135 -0
- universal_mcp/applications/clickup/__init__.py +1 -0
- universal_mcp/applications/clickup/app.py +5009 -0
- universal_mcp/applications/coda/README.md +108 -0
- universal_mcp/applications/coda/__init__.py +1 -0
- universal_mcp/applications/coda/app.py +3671 -0
- universal_mcp/applications/confluence/README.md +198 -0
- universal_mcp/applications/confluence/__init__.py +1 -0
- universal_mcp/applications/confluence/app.py +6273 -0
- universal_mcp/applications/contentful/README.md +17 -0
- universal_mcp/applications/contentful/__init__.py +1 -0
- universal_mcp/applications/contentful/app.py +364 -0
- universal_mcp/applications/crustdata/README.md +25 -0
- universal_mcp/applications/crustdata/__init__.py +1 -0
- universal_mcp/applications/crustdata/app.py +586 -0
- universal_mcp/applications/dialpad/README.md +202 -0
- universal_mcp/applications/dialpad/__init__.py +1 -0
- universal_mcp/applications/dialpad/app.py +5949 -0
- universal_mcp/applications/digitalocean/README.md +463 -0
- universal_mcp/applications/digitalocean/__init__.py +1 -0
- universal_mcp/applications/digitalocean/app.py +20835 -0
- universal_mcp/applications/domain-checker/README.md +13 -0
- universal_mcp/applications/domain-checker/__init__.py +1 -0
- universal_mcp/applications/domain-checker/app.py +265 -0
- universal_mcp/applications/e2b/README.md +12 -0
- universal_mcp/applications/e2b/__init__.py +1 -0
- universal_mcp/applications/e2b/app.py +187 -0
- universal_mcp/applications/elevenlabs/README.md +88 -0
- universal_mcp/applications/elevenlabs/__init__.py +1 -0
- universal_mcp/applications/elevenlabs/app.py +3235 -0
- universal_mcp/applications/exa/README.md +15 -0
- universal_mcp/applications/exa/__init__.py +1 -0
- universal_mcp/applications/exa/app.py +221 -0
- universal_mcp/applications/falai/README.md +17 -0
- universal_mcp/applications/falai/__init__.py +1 -0
- universal_mcp/applications/falai/app.py +331 -0
- universal_mcp/applications/figma/README.md +49 -0
- universal_mcp/applications/figma/__init__.py +1 -0
- universal_mcp/applications/figma/app.py +1090 -0
- universal_mcp/applications/firecrawl/README.md +20 -0
- universal_mcp/applications/firecrawl/__init__.py +1 -0
- universal_mcp/applications/firecrawl/app.py +514 -0
- universal_mcp/applications/fireflies/README.md +25 -0
- universal_mcp/applications/fireflies/__init__.py +1 -0
- universal_mcp/applications/fireflies/app.py +506 -0
- universal_mcp/applications/fpl/README.md +23 -0
- universal_mcp/applications/fpl/__init__.py +1 -0
- universal_mcp/applications/fpl/app.py +1327 -0
- universal_mcp/applications/fpl/utils/api.py +142 -0
- universal_mcp/applications/fpl/utils/fixtures.py +629 -0
- universal_mcp/applications/fpl/utils/helper.py +982 -0
- universal_mcp/applications/fpl/utils/league_utils.py +546 -0
- universal_mcp/applications/fpl/utils/position_utils.py +68 -0
- universal_mcp/applications/ghost-content/README.md +25 -0
- universal_mcp/applications/ghost-content/__init__.py +1 -0
- universal_mcp/applications/ghost-content/app.py +654 -0
- universal_mcp/applications/github/README.md +1049 -0
- universal_mcp/applications/github/__init__.py +1 -0
- universal_mcp/applications/github/app.py +50600 -0
- universal_mcp/applications/gong/README.md +63 -0
- universal_mcp/applications/gong/__init__.py +1 -0
- universal_mcp/applications/gong/app.py +2297 -0
- universal_mcp/applications/google-ads/README.md +0 -0
- universal_mcp/applications/google-ads/__init__.py +1 -0
- universal_mcp/applications/google-ads/app.py +23 -0
- universal_mcp/applications/google-calendar/README.md +21 -0
- universal_mcp/applications/google-calendar/__init__.py +1 -0
- universal_mcp/applications/google-calendar/app.py +574 -0
- universal_mcp/applications/google-docs/README.md +25 -0
- universal_mcp/applications/google-docs/__init__.py +1 -0
- universal_mcp/applications/google-docs/app.py +760 -0
- universal_mcp/applications/google-drive/README.md +68 -0
- universal_mcp/applications/google-drive/__init__.py +1 -0
- universal_mcp/applications/google-drive/app.py +4936 -0
- universal_mcp/applications/google-gemini/README.md +25 -0
- universal_mcp/applications/google-gemini/__init__.py +1 -0
- universal_mcp/applications/google-gemini/app.py +663 -0
- universal_mcp/applications/google-mail/README.md +31 -0
- universal_mcp/applications/google-mail/__init__.py +1 -0
- universal_mcp/applications/google-mail/app.py +1354 -0
- universal_mcp/applications/google-searchconsole/README.md +21 -0
- universal_mcp/applications/google-searchconsole/__init__.py +1 -0
- universal_mcp/applications/google-searchconsole/app.py +320 -0
- universal_mcp/applications/google-sheet/README.md +36 -0
- universal_mcp/applications/google-sheet/__init__.py +1 -0
- universal_mcp/applications/google-sheet/app.py +1941 -0
- universal_mcp/applications/hashnode/README.md +20 -0
- universal_mcp/applications/hashnode/__init__.py +1 -0
- universal_mcp/applications/hashnode/app.py +455 -0
- universal_mcp/applications/heygen/README.md +44 -0
- universal_mcp/applications/heygen/__init__.py +1 -0
- universal_mcp/applications/heygen/app.py +961 -0
- universal_mcp/applications/http-tools/README.md +16 -0
- universal_mcp/applications/http-tools/__init__.py +1 -0
- universal_mcp/applications/http-tools/app.py +153 -0
- universal_mcp/applications/hubspot/README.md +239 -0
- universal_mcp/applications/hubspot/__init__.py +1 -0
- universal_mcp/applications/hubspot/app.py +416 -0
- universal_mcp/applications/jira/README.md +600 -0
- universal_mcp/applications/jira/__init__.py +1 -0
- universal_mcp/applications/jira/app.py +28804 -0
- universal_mcp/applications/klaviyo/README.md +313 -0
- universal_mcp/applications/klaviyo/__init__.py +1 -0
- universal_mcp/applications/klaviyo/app.py +11236 -0
- universal_mcp/applications/linkedin/README.md +15 -0
- universal_mcp/applications/linkedin/__init__.py +1 -0
- universal_mcp/applications/linkedin/app.py +243 -0
- universal_mcp/applications/mailchimp/README.md +281 -0
- universal_mcp/applications/mailchimp/__init__.py +1 -0
- universal_mcp/applications/mailchimp/app.py +10937 -0
- universal_mcp/applications/markitdown/README.md +12 -0
- universal_mcp/applications/markitdown/__init__.py +1 -0
- universal_mcp/applications/markitdown/app.py +63 -0
- universal_mcp/applications/miro/README.md +151 -0
- universal_mcp/applications/miro/__init__.py +1 -0
- universal_mcp/applications/miro/app.py +5429 -0
- universal_mcp/applications/ms-teams/README.md +42 -0
- universal_mcp/applications/ms-teams/__init__.py +1 -0
- universal_mcp/applications/ms-teams/app.py +1823 -0
- universal_mcp/applications/neon/README.md +74 -0
- universal_mcp/applications/neon/__init__.py +1 -0
- universal_mcp/applications/neon/app.py +2018 -0
- universal_mcp/applications/notion/README.md +30 -0
- universal_mcp/applications/notion/__init__.py +1 -0
- universal_mcp/applications/notion/app.py +527 -0
- universal_mcp/applications/openai/README.md +22 -0
- universal_mcp/applications/openai/__init__.py +1 -0
- universal_mcp/applications/openai/app.py +759 -0
- universal_mcp/applications/outlook/README.md +20 -0
- universal_mcp/applications/outlook/__init__.py +1 -0
- universal_mcp/applications/outlook/app.py +444 -0
- universal_mcp/applications/perplexity/README.md +12 -0
- universal_mcp/applications/perplexity/__init__.py +1 -0
- universal_mcp/applications/perplexity/app.py +65 -0
- universal_mcp/applications/pipedrive/README.md +284 -0
- universal_mcp/applications/pipedrive/__init__.py +1 -0
- universal_mcp/applications/pipedrive/app.py +12924 -0
- universal_mcp/applications/posthog/README.md +132 -0
- universal_mcp/applications/posthog/__init__.py +1 -0
- universal_mcp/applications/posthog/app.py +7125 -0
- universal_mcp/applications/reddit/README.md +135 -0
- universal_mcp/applications/reddit/__init__.py +1 -0
- universal_mcp/applications/reddit/app.py +4652 -0
- universal_mcp/applications/replicate/README.md +18 -0
- universal_mcp/applications/replicate/__init__.py +1 -0
- universal_mcp/applications/replicate/app.py +495 -0
- universal_mcp/applications/resend/README.md +40 -0
- universal_mcp/applications/resend/__init__.py +1 -0
- universal_mcp/applications/resend/app.py +881 -0
- universal_mcp/applications/retell/README.md +21 -0
- universal_mcp/applications/retell/__init__.py +1 -0
- universal_mcp/applications/retell/app.py +333 -0
- universal_mcp/applications/rocketlane/README.md +70 -0
- universal_mcp/applications/rocketlane/__init__.py +1 -0
- universal_mcp/applications/rocketlane/app.py +4346 -0
- universal_mcp/applications/semanticscholar/README.md +25 -0
- universal_mcp/applications/semanticscholar/__init__.py +1 -0
- universal_mcp/applications/semanticscholar/app.py +482 -0
- universal_mcp/applications/semrush/README.md +44 -0
- universal_mcp/applications/semrush/__init__.py +1 -0
- universal_mcp/applications/semrush/app.py +2081 -0
- universal_mcp/applications/sendgrid/README.md +362 -0
- universal_mcp/applications/sendgrid/__init__.py +1 -0
- universal_mcp/applications/sendgrid/app.py +9752 -0
- universal_mcp/applications/sentry/README.md +186 -0
- universal_mcp/applications/sentry/__init__.py +1 -0
- universal_mcp/applications/sentry/app.py +7471 -0
- universal_mcp/applications/serpapi/README.md +14 -0
- universal_mcp/applications/serpapi/__init__.py +1 -0
- universal_mcp/applications/serpapi/app.py +293 -0
- universal_mcp/applications/sharepoint/README.md +0 -0
- universal_mcp/applications/sharepoint/__init__.py +1 -0
- universal_mcp/applications/sharepoint/app.py +215 -0
- universal_mcp/applications/shopify/README.md +321 -0
- universal_mcp/applications/shopify/__init__.py +1 -0
- universal_mcp/applications/shopify/app.py +15392 -0
- universal_mcp/applications/shortcut/README.md +128 -0
- universal_mcp/applications/shortcut/__init__.py +1 -0
- universal_mcp/applications/shortcut/app.py +4478 -0
- universal_mcp/applications/slack/README.md +0 -0
- universal_mcp/applications/slack/__init__.py +1 -0
- universal_mcp/applications/slack/app.py +570 -0
- universal_mcp/applications/spotify/README.md +91 -0
- universal_mcp/applications/spotify/__init__.py +1 -0
- universal_mcp/applications/spotify/app.py +2526 -0
- universal_mcp/applications/supabase/README.md +87 -0
- universal_mcp/applications/supabase/__init__.py +1 -0
- universal_mcp/applications/supabase/app.py +2970 -0
- universal_mcp/applications/tavily/README.md +12 -0
- universal_mcp/applications/tavily/__init__.py +1 -0
- universal_mcp/applications/tavily/app.py +51 -0
- universal_mcp/applications/trello/README.md +266 -0
- universal_mcp/applications/trello/__init__.py +1 -0
- universal_mcp/applications/trello/app.py +10875 -0
- universal_mcp/applications/twillo/README.md +0 -0
- universal_mcp/applications/twillo/__init__.py +1 -0
- universal_mcp/applications/twillo/app.py +269 -0
- universal_mcp/applications/twitter/README.md +100 -0
- universal_mcp/applications/twitter/__init__.py +1 -0
- universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
- universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
- universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
- universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
- universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
- universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
- universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
- universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
- universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
- universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
- universal_mcp/applications/twitter/app.py +46 -0
- universal_mcp/applications/unipile/README.md +28 -0
- universal_mcp/applications/unipile/__init__.py +1 -0
- universal_mcp/applications/unipile/app.py +829 -0
- universal_mcp/applications/whatsapp/README.md +23 -0
- universal_mcp/applications/whatsapp/__init__.py +1 -0
- universal_mcp/applications/whatsapp/app.py +595 -0
- universal_mcp/applications/whatsapp-business/README.md +34 -0
- universal_mcp/applications/whatsapp-business/__init__.py +1 -0
- universal_mcp/applications/whatsapp-business/app.py +1065 -0
- universal_mcp/applications/wrike/README.md +46 -0
- universal_mcp/applications/wrike/__init__.py +1 -0
- universal_mcp/applications/wrike/app.py +1583 -0
- universal_mcp/applications/youtube/README.md +57 -0
- universal_mcp/applications/youtube/__init__.py +1 -0
- universal_mcp/applications/youtube/app.py +1696 -0
- universal_mcp/applications/zenquotes/README.md +12 -0
- universal_mcp/applications/zenquotes/__init__.py +1 -0
- universal_mcp/applications/zenquotes/app.py +31 -0
- universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
- universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
- universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
- universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from universal_mcp.applications.application import APIApplication
|
|
6
|
+
from universal_mcp.integrations import Integration
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GhostContentApp(APIApplication):
|
|
10
|
+
"""
|
|
11
|
+
Application for interacting with the Ghost Content API.
|
|
12
|
+
Handles operations related to posts, pages, tags, authors, tiers, newsletters,
|
|
13
|
+
offers, products, collections, and general site information.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, integration: Integration) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initialize the GhostContentApp.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
integration: The integration configuration containing the Ghost site URL
|
|
22
|
+
and Content API key.
|
|
23
|
+
It is expected that the integration provides 'url' (e.g.,
|
|
24
|
+
"https://your-ghost-site.com") and 'key' (the Content API key)
|
|
25
|
+
via `integration.get_credentials()`.
|
|
26
|
+
"""
|
|
27
|
+
super().__init__(name="ghost-content", integration=integration)
|
|
28
|
+
self._base_url = None
|
|
29
|
+
self._api_key = None # Cache the API key
|
|
30
|
+
self._version = None # Cache the version
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def base_url(self) -> str:
|
|
34
|
+
"""
|
|
35
|
+
Get the base URL for the Ghost Content API.
|
|
36
|
+
This is constructed from the integration's credentials.
|
|
37
|
+
"""
|
|
38
|
+
if not self._base_url:
|
|
39
|
+
credentials = self.integration.get_credentials()
|
|
40
|
+
ghost_url = credentials.get("url") or credentials.get("admin_domain")
|
|
41
|
+
if not ghost_url:
|
|
42
|
+
logger.error(
|
|
43
|
+
"GhostContentApp: Missing 'url' or 'admin_domain' in integration credentials."
|
|
44
|
+
)
|
|
45
|
+
raise ValueError(
|
|
46
|
+
"Integration credentials must include 'url' or 'admin_domain' for the Ghost site."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
self._base_url = f"{ghost_url.rstrip('/')}/api/content/"
|
|
50
|
+
logger.info(f"GhostContentApp: Constructed base URL as {self._base_url}")
|
|
51
|
+
return self._base_url
|
|
52
|
+
|
|
53
|
+
@base_url.setter
|
|
54
|
+
def base_url(self, base_url: str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Set the base URL for the Ghost Content API.
|
|
57
|
+
This is useful for testing or if the base URL changes.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
base_url: The new base URL to set.
|
|
61
|
+
"""
|
|
62
|
+
self._base_url = base_url
|
|
63
|
+
logger.info(f"GhostContentApp: Base URL set to {self._base_url}")
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def _get_api_key(self) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Retrieves the Ghost Content API key from integration credentials.
|
|
69
|
+
Caches the key after the first retrieval.
|
|
70
|
+
"""
|
|
71
|
+
if not self._api_key:
|
|
72
|
+
credentials = self.integration.get_credentials()
|
|
73
|
+
api_key = (
|
|
74
|
+
credentials.get("key")
|
|
75
|
+
or credentials.get("api_key")
|
|
76
|
+
or credentials.get("API_KEY")
|
|
77
|
+
)
|
|
78
|
+
if not api_key:
|
|
79
|
+
logger.error(
|
|
80
|
+
"GhostContentApp: Content API key ('key') not found in integration credentials."
|
|
81
|
+
)
|
|
82
|
+
raise ValueError(
|
|
83
|
+
"Integration credentials must include the Ghost Content API 'key'."
|
|
84
|
+
)
|
|
85
|
+
self._api_key = api_key
|
|
86
|
+
return self._api_key
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def _get_version(self) -> str:
|
|
90
|
+
"""
|
|
91
|
+
Retrieves the Ghost Content API version from integration credentials.
|
|
92
|
+
Caches the version after the first retrieval.
|
|
93
|
+
"""
|
|
94
|
+
if not self._version:
|
|
95
|
+
credentials = self.integration.get_credentials()
|
|
96
|
+
version = credentials.get("api_version")
|
|
97
|
+
if not version:
|
|
98
|
+
logger.warning(
|
|
99
|
+
"GhostContentApp: 'version' not found in integration credentials. Defaulting to 'v5.0'."
|
|
100
|
+
)
|
|
101
|
+
version = "v5.0" # Default to a common version if not specified
|
|
102
|
+
self._version = version
|
|
103
|
+
return self._version
|
|
104
|
+
|
|
105
|
+
def _get_headers(self) -> dict[str, str]:
|
|
106
|
+
"""
|
|
107
|
+
Get the headers for Ghost Content API requests.
|
|
108
|
+
Overrides the base class method to include the `Accept-Version` header.
|
|
109
|
+
"""
|
|
110
|
+
headers = super()._get_headers() # Get base headers (e.g., Content-Type)
|
|
111
|
+
|
|
112
|
+
# Add the Accept-Version header as per Ghost Content API documentation
|
|
113
|
+
headers["Accept-Version"] = self._get_version
|
|
114
|
+
logger.debug(
|
|
115
|
+
f"GhostContentApp: Using Accept-Version: {self._get_version} in headers."
|
|
116
|
+
)
|
|
117
|
+
return headers
|
|
118
|
+
|
|
119
|
+
def _build_common_params(
|
|
120
|
+
self,
|
|
121
|
+
include: list[str] | None = None,
|
|
122
|
+
fields: list[str] | None = None,
|
|
123
|
+
filter: str | None = None, # Changed from filter_str to filter
|
|
124
|
+
limit: int | None = None,
|
|
125
|
+
order: str | None = None,
|
|
126
|
+
page: int | None = None,
|
|
127
|
+
formats: list[str] | None = None, # Specific to posts/pages for content format
|
|
128
|
+
visibility: str | None = None, # Specific to posts/pages/tiers for visibility
|
|
129
|
+
) -> dict[str, Any]:
|
|
130
|
+
"""
|
|
131
|
+
Helper to build common query parameters for Ghost Content API requests,
|
|
132
|
+
including the mandatory API key.
|
|
133
|
+
"""
|
|
134
|
+
params: dict[str, Any] = {"key": self._get_api_key}
|
|
135
|
+
|
|
136
|
+
if include:
|
|
137
|
+
params["include"] = ",".join(include)
|
|
138
|
+
if fields:
|
|
139
|
+
params["fields"] = ",".join(fields)
|
|
140
|
+
if filter: # Use 'filter' here
|
|
141
|
+
params["filter"] = filter
|
|
142
|
+
if limit is not None:
|
|
143
|
+
params["limit"] = limit
|
|
144
|
+
if order:
|
|
145
|
+
params["order"] = order
|
|
146
|
+
if page is not None:
|
|
147
|
+
params["page"] = page
|
|
148
|
+
if formats:
|
|
149
|
+
params["formats"] = ",".join(formats)
|
|
150
|
+
if visibility:
|
|
151
|
+
params["visibility"] = visibility
|
|
152
|
+
return params
|
|
153
|
+
|
|
154
|
+
# --- Posts Tools ---
|
|
155
|
+
def browse_posts(
|
|
156
|
+
self,
|
|
157
|
+
include: list[str] | None = None,
|
|
158
|
+
fields: list[str] | None = None,
|
|
159
|
+
filter: str | None = None,
|
|
160
|
+
limit: int | None = None,
|
|
161
|
+
page: int | None = None,
|
|
162
|
+
order: str | None = None,
|
|
163
|
+
formats: list[str] | None = None,
|
|
164
|
+
) -> dict[str, Any]: # Changed return type to Dict[str, Any]
|
|
165
|
+
"""
|
|
166
|
+
Retrieves and browses posts from a data source based on provided parameters.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
include: A list of fields to include in the response.
|
|
170
|
+
fields: A list of specific fields to retrieve.
|
|
171
|
+
filter: A string to filter the posts by.
|
|
172
|
+
limit: The maximum number of posts to return.
|
|
173
|
+
page: The page number to start retrieving posts from.
|
|
174
|
+
order: The order in which to retrieve posts.
|
|
175
|
+
formats: A list of formats in which to retrieve posts.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
The result of the posts retrieval, which may be in various formats depending on the request parameters.
|
|
179
|
+
|
|
180
|
+
Raises:
|
|
181
|
+
httpx.HTTPError: An exception might be raised if there is an issue with the request execution, such as network errors or invalid parameters.
|
|
182
|
+
|
|
183
|
+
Tags:
|
|
184
|
+
browse, fetch, posts, management, important
|
|
185
|
+
"""
|
|
186
|
+
url = f"{self.base_url}posts/"
|
|
187
|
+
# Removed 'visibility' from params as it's not in the method signature
|
|
188
|
+
params = self._build_common_params(
|
|
189
|
+
include=include,
|
|
190
|
+
fields=fields,
|
|
191
|
+
filter=filter,
|
|
192
|
+
limit=limit,
|
|
193
|
+
page=page,
|
|
194
|
+
order=order,
|
|
195
|
+
formats=formats,
|
|
196
|
+
)
|
|
197
|
+
response = self._get(url, params=params)
|
|
198
|
+
return response.json()
|
|
199
|
+
|
|
200
|
+
def read_post_by_id(
|
|
201
|
+
self,
|
|
202
|
+
id: str,
|
|
203
|
+
include: list[str] | None = None,
|
|
204
|
+
fields: list[str] | None = None,
|
|
205
|
+
formats: list[str] | None = None,
|
|
206
|
+
) -> dict[str, Any]: # Changed return type
|
|
207
|
+
"""
|
|
208
|
+
Retrieves a post by its ID, optionally including additional data or specific fields.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
id: The unique identifier of the post to retrieve.
|
|
212
|
+
include: Optional list of additional data to include in the response.
|
|
213
|
+
fields: Optional list of specific fields to retrieve for the post.
|
|
214
|
+
formats: Optional list of formats for the post data.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The retrieved post data in the specified format.
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
httpx.HTTPError: If the API request fails.
|
|
221
|
+
|
|
222
|
+
Tags:
|
|
223
|
+
read, post, management
|
|
224
|
+
"""
|
|
225
|
+
url = f"{self.base_url}posts/{id}/"
|
|
226
|
+
params = self._build_common_params(
|
|
227
|
+
include=include, fields=fields, formats=formats
|
|
228
|
+
)
|
|
229
|
+
response = self._get(url, params=params)
|
|
230
|
+
return response.json()
|
|
231
|
+
|
|
232
|
+
def read_post_by_slug(
|
|
233
|
+
self,
|
|
234
|
+
slug: str,
|
|
235
|
+
include: list[str] | None = None,
|
|
236
|
+
fields: list[str] | None = None,
|
|
237
|
+
formats: list[str] | None = None,
|
|
238
|
+
) -> dict[str, Any]: # Changed return type
|
|
239
|
+
"""
|
|
240
|
+
Retrieves a post by its slug, with optional parameters to specify included data, select specific fields, or request particular data formats.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
slug: Unique slug identifier of the post to retrieve.
|
|
244
|
+
include: Optional list of related objects to include with the post.
|
|
245
|
+
fields: Optional list of fields to include in the returned post data.
|
|
246
|
+
formats: Optional list of data formats in which to return the post.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
The retrieved post data or response payload, as returned by the underlying GET request executor.
|
|
250
|
+
|
|
251
|
+
Raises:
|
|
252
|
+
httpx.HTTPError: May be raised if the underlying GET request fails, e.g., due to network issues, invalid parameters, or unauthorized access.
|
|
253
|
+
|
|
254
|
+
Tags:
|
|
255
|
+
read, post, fetch, management
|
|
256
|
+
"""
|
|
257
|
+
url = f"{self.base_url}posts/slug/{slug}/"
|
|
258
|
+
params = self._build_common_params(
|
|
259
|
+
include=include, fields=fields, formats=formats
|
|
260
|
+
)
|
|
261
|
+
response = self._get(url, params=params)
|
|
262
|
+
return response.json()
|
|
263
|
+
|
|
264
|
+
# --- Authors Tools ---
|
|
265
|
+
def browse_authors(
|
|
266
|
+
self,
|
|
267
|
+
include: list[str] | None = None,
|
|
268
|
+
fields: list[str] | None = None,
|
|
269
|
+
filter: str | None = None,
|
|
270
|
+
limit: int | None = None,
|
|
271
|
+
page: int | None = None,
|
|
272
|
+
order: str | None = None,
|
|
273
|
+
) -> dict[str, Any]: # Changed return type
|
|
274
|
+
"""
|
|
275
|
+
Browse authors using various filtering and pagination options.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
include: Optional list of fields to include in the response.
|
|
279
|
+
fields: Optional list of specific fields to retrieve.
|
|
280
|
+
filter: Optional string filter to apply to the results.
|
|
281
|
+
limit: Optional integer specifying the maximum number of results to return.
|
|
282
|
+
page: Optional integer indicating the page number.
|
|
283
|
+
order: Optional string defining the order of results.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Any data returned from the GET request to the authors endpoint.
|
|
287
|
+
|
|
288
|
+
Raises:
|
|
289
|
+
httpx.HTTPError: If the API request fails.
|
|
290
|
+
|
|
291
|
+
Tags:
|
|
292
|
+
list, management, important
|
|
293
|
+
"""
|
|
294
|
+
url = f"{self.base_url}authors/"
|
|
295
|
+
params = self._build_common_params(
|
|
296
|
+
include=include,
|
|
297
|
+
fields=fields,
|
|
298
|
+
filter=filter,
|
|
299
|
+
limit=limit,
|
|
300
|
+
page=page,
|
|
301
|
+
order=order,
|
|
302
|
+
)
|
|
303
|
+
response = self._get(url, params=params)
|
|
304
|
+
return response.json()
|
|
305
|
+
|
|
306
|
+
def read_author_by_id(
|
|
307
|
+
self,
|
|
308
|
+
id: str,
|
|
309
|
+
include: list[str] | None = None,
|
|
310
|
+
fields: list[str] | None = None,
|
|
311
|
+
) -> dict[str, Any]: # Changed return type
|
|
312
|
+
"""
|
|
313
|
+
Read an author from the database by their unique ID.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
id: The unique identifier of the author.
|
|
317
|
+
include: Optional list of related resources to include in the response.
|
|
318
|
+
fields: Optional list of fields to retrieve from the author record.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
The author data as a JSON response or other arbitrary data type.
|
|
322
|
+
|
|
323
|
+
Raises:
|
|
324
|
+
httpx.HTTPError: If the API request fails.
|
|
325
|
+
|
|
326
|
+
Tags:
|
|
327
|
+
read, author, data-access
|
|
328
|
+
"""
|
|
329
|
+
url = f"{self.base_url}authors/{id}/"
|
|
330
|
+
params = self._build_common_params(include=include, fields=fields)
|
|
331
|
+
response = self._get(url, params=params)
|
|
332
|
+
return response.json()
|
|
333
|
+
|
|
334
|
+
def read_author_by_slug(
|
|
335
|
+
self,
|
|
336
|
+
slug: str,
|
|
337
|
+
include: list[str] | None = None,
|
|
338
|
+
fields: list[str] | None = None,
|
|
339
|
+
) -> dict[str, Any]: # Changed return type
|
|
340
|
+
"""
|
|
341
|
+
Retrieve an author's information by their slug.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
slug: The unique slug of the author to retrieve.
|
|
345
|
+
include: Optional list of fields to include in the response.
|
|
346
|
+
fields: Optional list of fields to request in the response.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
The result of the GET request to retrieve the author's information.
|
|
350
|
+
|
|
351
|
+
Raises:
|
|
352
|
+
httpx.HTTPError: If the API request fails.
|
|
353
|
+
|
|
354
|
+
Tags:
|
|
355
|
+
fetch, author, management
|
|
356
|
+
"""
|
|
357
|
+
url = f"{self.base_url}authors/slug/{slug}/"
|
|
358
|
+
params = self._build_common_params(include=include, fields=fields)
|
|
359
|
+
response = self._get(url, params=params)
|
|
360
|
+
return response.json()
|
|
361
|
+
|
|
362
|
+
# --- Tags Tools ---
|
|
363
|
+
def browse_tags(
|
|
364
|
+
self,
|
|
365
|
+
include: list[str] | None = None,
|
|
366
|
+
fields: list[str] | None = None,
|
|
367
|
+
filter: str | None = None,
|
|
368
|
+
limit: int | None = None,
|
|
369
|
+
page: int | None = None,
|
|
370
|
+
order: str | None = None,
|
|
371
|
+
) -> dict[str, Any]: # Changed return type
|
|
372
|
+
"""
|
|
373
|
+
Browse and retrieve tags based on specified parameters.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
include: Optional list of tags or fields to include.
|
|
377
|
+
fields: Optional list of specific fields to retrieve.
|
|
378
|
+
filter: Optional filter expression to apply.
|
|
379
|
+
limit: Optional limit on the number of tags to return.
|
|
380
|
+
page: Optional page number for pagination.
|
|
381
|
+
order: Optional ordering criteria for the returned tags.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
Response from the GET request to retrieve tags.
|
|
385
|
+
|
|
386
|
+
Raises:
|
|
387
|
+
httpx.HTTPError: Raised if the connection to the server fails, or request times out.
|
|
388
|
+
|
|
389
|
+
Tags:
|
|
390
|
+
browse, tags, management, important
|
|
391
|
+
"""
|
|
392
|
+
url = f"{self.base_url}tags/"
|
|
393
|
+
params = self._build_common_params(
|
|
394
|
+
include=include,
|
|
395
|
+
fields=fields,
|
|
396
|
+
filter=filter,
|
|
397
|
+
limit=limit,
|
|
398
|
+
page=page,
|
|
399
|
+
order=order,
|
|
400
|
+
)
|
|
401
|
+
response = self._get(url, params=params)
|
|
402
|
+
return response.json()
|
|
403
|
+
|
|
404
|
+
def read_tag_by_id(
|
|
405
|
+
self,
|
|
406
|
+
id: str,
|
|
407
|
+
include: list[str] | None = None,
|
|
408
|
+
fields: list[str] | None = None,
|
|
409
|
+
) -> dict[str, Any]: # Changed return type
|
|
410
|
+
"""
|
|
411
|
+
Retrieves a tag's details by its unique identifier, optionally filtering by included and field sets.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
id: str: The unique identifier of the tag to retrieve.
|
|
415
|
+
include: Optional[List[str]]: Additional related resources or attributes to include in the response.
|
|
416
|
+
fields: Optional[List[str]]: Specific fields to return in the response.
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
Any: The retrieved tag object, with details as specified by the included and field parameters. The exact type depends on the server response.
|
|
420
|
+
|
|
421
|
+
Raises:
|
|
422
|
+
httpx.HTTPError: Depending on the backend, may raise connection, authentication, or data retrieval exceptions.
|
|
423
|
+
|
|
424
|
+
Tags:
|
|
425
|
+
read, tag, search, fetch, api, management
|
|
426
|
+
"""
|
|
427
|
+
url = f"{self.base_url}tags/{id}/"
|
|
428
|
+
params = self._build_common_params(include=include, fields=fields)
|
|
429
|
+
response = self._get(url, params=params)
|
|
430
|
+
return response.json()
|
|
431
|
+
|
|
432
|
+
def read_tag_by_slug(
|
|
433
|
+
self,
|
|
434
|
+
slug: str,
|
|
435
|
+
include: list[str] | None = None,
|
|
436
|
+
fields: list[str] | None = None,
|
|
437
|
+
) -> dict[str, Any]: # Changed return type
|
|
438
|
+
"""
|
|
439
|
+
Retrieve tag information identified by a unique slug, with optional inclusion of related data and selective fields.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
slug: str: The unique slug identifier of the tag to retrieve.
|
|
443
|
+
include: Optional[List[str]]: A list of related resource names to include in the response, or None to include none.
|
|
444
|
+
fields: Optional[List[str]]: A list of specific fields to return for the tag, or None to return all fields.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
Any: The data corresponding to the requested tag, potentially including related resources and filtered fields, as returned by the GET request.
|
|
448
|
+
|
|
449
|
+
Raises:
|
|
450
|
+
httpx.HTTPError: If the underlying GET request fails due to network issues, invalid slug, or server errors.
|
|
451
|
+
|
|
452
|
+
Tags:
|
|
453
|
+
read, retrieve, get
|
|
454
|
+
"""
|
|
455
|
+
url = f"{self.base_url}tags/slug/{slug}/"
|
|
456
|
+
params = self._build_common_params(include=include, fields=fields)
|
|
457
|
+
response = self._get(url, params=params)
|
|
458
|
+
return response.json()
|
|
459
|
+
|
|
460
|
+
# --- Pages Tools ---
|
|
461
|
+
def browse_pages(
|
|
462
|
+
self,
|
|
463
|
+
include: list[str] | None = None,
|
|
464
|
+
fields: list[str] | None = None,
|
|
465
|
+
filter: str | None = None,
|
|
466
|
+
limit: int | None = None,
|
|
467
|
+
page: int | None = None,
|
|
468
|
+
order: str | None = None,
|
|
469
|
+
formats: list[str] | None = None,
|
|
470
|
+
) -> dict[str, Any]: # Changed return type
|
|
471
|
+
"""
|
|
472
|
+
Retrieves a list of pages using optional filtering, pagination, and formatting parameters.
|
|
473
|
+
|
|
474
|
+
Args:
|
|
475
|
+
include: Optional list of related resources or entities to include in the response.
|
|
476
|
+
fields: Optional list of specific fields to include for each page in the response.
|
|
477
|
+
filter: Optional string to filter the pages based on certain criteria.
|
|
478
|
+
limit: Optional integer specifying the maximum number of pages to return.
|
|
479
|
+
page: Optional integer specifying the page number for pagination.
|
|
480
|
+
order: Optional string defining the sorting order of the returned pages.
|
|
481
|
+
formats: Optional list of formats that the pages should be returned in.
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
The result of the GET request to the 'pages/' endpoint, typically a collection of pages matching the query parameters.
|
|
485
|
+
|
|
486
|
+
Raises:
|
|
487
|
+
httpx.HTTPError: If the underlying GET request fails due to network issues, invalid parameters, or server errors.
|
|
488
|
+
|
|
489
|
+
Tags:
|
|
490
|
+
browse, list, management, important
|
|
491
|
+
"""
|
|
492
|
+
url = f"{self.base_url}pages/"
|
|
493
|
+
# Removed 'visibility' from params as it's not in the method signature
|
|
494
|
+
params = self._build_common_params(
|
|
495
|
+
include=include,
|
|
496
|
+
fields=fields,
|
|
497
|
+
filter=filter,
|
|
498
|
+
limit=limit,
|
|
499
|
+
page=page,
|
|
500
|
+
order=order,
|
|
501
|
+
formats=formats,
|
|
502
|
+
)
|
|
503
|
+
response = self._get(url, params=params)
|
|
504
|
+
return response.json()
|
|
505
|
+
|
|
506
|
+
def read_page_by_id(
|
|
507
|
+
self,
|
|
508
|
+
id: str,
|
|
509
|
+
include: list[str] | None = None,
|
|
510
|
+
fields: list[str] | None = None,
|
|
511
|
+
formats: list[str] | None = None,
|
|
512
|
+
) -> dict[str, Any]: # Changed return type
|
|
513
|
+
"""
|
|
514
|
+
Read a page by ID, allowing for optional inclusion of additional data, specific fields, and formats.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
id: The unique identifier of the page to be read.
|
|
518
|
+
include: Optional list of related data to include in the response.
|
|
519
|
+
fields: Optional list of fields to filter the response by.
|
|
520
|
+
formats: Optional list of formats for the response data.
|
|
521
|
+
|
|
522
|
+
Returns:
|
|
523
|
+
The result of the GET request to read the page.
|
|
524
|
+
|
|
525
|
+
Raises:
|
|
526
|
+
httpx.HTTPError: If the API request fails.
|
|
527
|
+
|
|
528
|
+
Tags:
|
|
529
|
+
read, page, data-retrieval
|
|
530
|
+
"""
|
|
531
|
+
url = f"{self.base_url}pages/{id}/"
|
|
532
|
+
params = self._build_common_params(
|
|
533
|
+
include=include, fields=fields, formats=formats
|
|
534
|
+
)
|
|
535
|
+
response = self._get(url, params=params)
|
|
536
|
+
return response.json()
|
|
537
|
+
|
|
538
|
+
def read_page_by_slug(
|
|
539
|
+
self,
|
|
540
|
+
slug: str,
|
|
541
|
+
include: list[str] | None = None,
|
|
542
|
+
fields: list[str] | None = None,
|
|
543
|
+
formats: list[str] | None = None,
|
|
544
|
+
) -> dict[str, Any]: # Changed return type
|
|
545
|
+
"""
|
|
546
|
+
Retrieve a page's content and metadata by its slug identifier, optionally including related data, specific fields, and content formats.
|
|
547
|
+
|
|
548
|
+
Args:
|
|
549
|
+
slug: The unique slug string identifying the page to be retrieved.
|
|
550
|
+
include: Optional list of related resource names to include in the response.
|
|
551
|
+
fields: Optional list of specific fields of the page to return.
|
|
552
|
+
formats: Optional list of content formats to retrieve for the page.
|
|
553
|
+
|
|
554
|
+
Returns:
|
|
555
|
+
The response from the GET request containing the page data, typically as a parsed JSON object or equivalent.
|
|
556
|
+
|
|
557
|
+
Raises:
|
|
558
|
+
httpx.HTTPError: If the underlying GET request fails due to network issues, invalid slug, or server errors.
|
|
559
|
+
|
|
560
|
+
Tags:
|
|
561
|
+
read, get, page, slug, http-request
|
|
562
|
+
"""
|
|
563
|
+
url = f"{self.base_url}pages/slug/{slug}/"
|
|
564
|
+
params = self._build_common_params(
|
|
565
|
+
include=include, fields=fields, formats=formats
|
|
566
|
+
)
|
|
567
|
+
response = self._get(url, params=params)
|
|
568
|
+
return response.json()
|
|
569
|
+
|
|
570
|
+
# --- Tiers Tool ---
|
|
571
|
+
def browse_tiers(
|
|
572
|
+
self,
|
|
573
|
+
include: list[str] | None = None,
|
|
574
|
+
fields: list[str] | None = None,
|
|
575
|
+
filter: str | None = None,
|
|
576
|
+
limit: int | None = None,
|
|
577
|
+
page: int | None = None,
|
|
578
|
+
order: str | None = None,
|
|
579
|
+
) -> dict[str, Any]: # Changed return type
|
|
580
|
+
"""
|
|
581
|
+
Browse tiers based on optional filters and pagination.
|
|
582
|
+
|
|
583
|
+
Args:
|
|
584
|
+
include: List of items to include in the response, if applicable.
|
|
585
|
+
fields: List of fields to retrieve from the tiers.
|
|
586
|
+
filter: String filter to apply to the tiers.
|
|
587
|
+
limit: Maximum number of tiers to return in the response.
|
|
588
|
+
page: Page number for pagination.
|
|
589
|
+
order: Ordering parameter for the tiers.
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
Response from the tiers browsing request.
|
|
593
|
+
|
|
594
|
+
Raises:
|
|
595
|
+
httpx.HTTPError: Raised on any issue during the execution of the GET request.
|
|
596
|
+
|
|
597
|
+
Tags:
|
|
598
|
+
browse, pagination, filter, management, important
|
|
599
|
+
"""
|
|
600
|
+
url = f"{self.base_url}tiers/"
|
|
601
|
+
# Removed 'visibility' from params as it's not in the method signature
|
|
602
|
+
params = self._build_common_params(
|
|
603
|
+
include=include,
|
|
604
|
+
fields=fields,
|
|
605
|
+
filter=filter,
|
|
606
|
+
limit=limit,
|
|
607
|
+
page=page,
|
|
608
|
+
order=order,
|
|
609
|
+
)
|
|
610
|
+
response = self._get(url, params=params)
|
|
611
|
+
return response.json()
|
|
612
|
+
|
|
613
|
+
# --- Settings Tool ---
|
|
614
|
+
def browse_settings(self) -> dict[str, Any]: # Changed return type
|
|
615
|
+
"""
|
|
616
|
+
Fetches site settings by making a GET request to the settings endpoint.
|
|
617
|
+
|
|
618
|
+
Args:
|
|
619
|
+
None: This function does not accept any parameters.
|
|
620
|
+
|
|
621
|
+
Returns:
|
|
622
|
+
The result of the GET request to retrieve site settings.
|
|
623
|
+
|
|
624
|
+
Raises:
|
|
625
|
+
httpx.HTTPError: If the API request fails.
|
|
626
|
+
|
|
627
|
+
Tags:
|
|
628
|
+
fetch, settings, management, important
|
|
629
|
+
"""
|
|
630
|
+
url = f"{self.base_url}settings/"
|
|
631
|
+
params = (
|
|
632
|
+
self._build_common_params()
|
|
633
|
+
) # Only the API key is needed for this endpoint via _build_common_params
|
|
634
|
+
response = self._get(url, params=params)
|
|
635
|
+
return response.json()
|
|
636
|
+
|
|
637
|
+
def list_tools(self) -> list[Callable]:
|
|
638
|
+
"""Returns a list of methods exposed as tools for the Ghost Content API."""
|
|
639
|
+
return [
|
|
640
|
+
self.browse_posts,
|
|
641
|
+
self.read_post_by_id,
|
|
642
|
+
self.read_post_by_slug,
|
|
643
|
+
self.browse_authors,
|
|
644
|
+
self.read_author_by_id,
|
|
645
|
+
self.read_author_by_slug,
|
|
646
|
+
self.browse_tags,
|
|
647
|
+
self.read_tag_by_id,
|
|
648
|
+
self.read_tag_by_slug,
|
|
649
|
+
self.browse_pages,
|
|
650
|
+
self.read_page_by_id,
|
|
651
|
+
self.read_page_by_slug,
|
|
652
|
+
self.browse_tiers,
|
|
653
|
+
self.browse_settings,
|
|
654
|
+
]
|