hostinger-api-mcp 3.24.3 → 3.25.1
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.
- package/CHANGELOG.md +33 -0
- package/README.md +31 -105
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/connect-domain/SKILL.md +4 -4
- package/skills/deploy-to-hosting/SKILL.md +1 -1
- package/skills/headless/SKILL.md +3 -3
- package/skills/headless/VERSION +2 -2
- package/skills/headless/steps/01-check-state/SKILL.md +1 -1
- package/skills/headless/steps/03-provision/SKILL.md +8 -8
- package/skills/headless/steps/03-provision/ecommerce/SKILL.md +4 -5
- package/skills/headless/steps/03-provision/webapp/SKILL.md +6 -7
- package/skills/headless/steps/03-provision/wordpress/SKILL.md +8 -9
- package/src/core/runtime.js +154 -1
- package/src/core/runtime.ts +154 -1
- package/src/core/skills.js +24 -24
- package/src/core/skills.ts +24 -24
- package/src/core/tools/all.js +193 -14
- package/src/core/tools/all.ts +193 -14
- package/src/core/tools/hosting.js +191 -12
- package/src/core/tools/hosting.ts +191 -12
- package/src/core/tools/wordpress.js +2 -2
- package/src/core/tools/wordpress.ts +2 -2
- package/src/servers/agency-hosting.js +1 -1
- package/src/servers/agency-hosting.ts +1 -1
- package/src/servers/agent-readiness.js +1 -1
- package/src/servers/agent-readiness.ts +1 -1
- package/src/servers/all.js +1 -1
- package/src/servers/all.ts +1 -1
- package/src/servers/billing.js +1 -1
- package/src/servers/billing.ts +1 -1
- package/src/servers/dns.js +1 -1
- package/src/servers/dns.ts +1 -1
- package/src/servers/domains.js +1 -1
- package/src/servers/domains.ts +1 -1
- package/src/servers/ecommerce.js +1 -1
- package/src/servers/ecommerce.ts +1 -1
- package/src/servers/horizons.js +1 -1
- package/src/servers/horizons.ts +1 -1
- package/src/servers/hosting.js +1 -1
- package/src/servers/hosting.ts +1 -1
- package/src/servers/mail.js +1 -1
- package/src/servers/mail.ts +1 -1
- package/src/servers/reach.js +1 -1
- package/src/servers/reach.ts +1 -1
- package/src/servers/vps.js +1 -1
- package/src/servers/vps.ts +1 -1
- package/src/servers/wordpress.js +1 -1
- package/src/servers/wordpress.ts +1 -1
- package/types.d.ts +99 -11
package/src/core/runtime.js
CHANGED
|
@@ -62,7 +62,7 @@ const GetSkillRequestSchema = z.object({
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* MCP Server for Hostinger API
|
|
65
|
-
* Generated from OpenAPI spec version 2.6.
|
|
65
|
+
* Generated from OpenAPI spec version 2.6.2
|
|
66
66
|
*/
|
|
67
67
|
class MCPServer {
|
|
68
68
|
constructor({ name, version, tools, instructions, skills = [] }) {
|
|
@@ -304,6 +304,14 @@ class MCPServer {
|
|
|
304
304
|
return await this.handleHostingWebsitesUpdateSettings(params);
|
|
305
305
|
case 'hosting_cache_clear':
|
|
306
306
|
return await this.handleHostingCacheClear(params);
|
|
307
|
+
case 'hosting_websites_list-domains':
|
|
308
|
+
return await this.handleHostingWebsitesListDomains(params);
|
|
309
|
+
case 'hosting_websites_add-domain':
|
|
310
|
+
return await this.handleHostingWebsitesAddDomain(params);
|
|
311
|
+
case 'hosting_websites_remove-domain':
|
|
312
|
+
return await this.handleHostingWebsitesRemoveDomain(params);
|
|
313
|
+
case 'hosting_websites_start-setup':
|
|
314
|
+
return await this.handleHostingWebsitesStartSetup(params);
|
|
307
315
|
case 'hosting_import-wordpress-website':
|
|
308
316
|
return await this.handleWordpressWebsiteImport(params);
|
|
309
317
|
case 'hosting_deploy-wordpress-plugin':
|
|
@@ -677,6 +685,14 @@ class MCPServer {
|
|
|
677
685
|
throw new Error('No website found for domain: ' + domain);
|
|
678
686
|
}
|
|
679
687
|
|
|
688
|
+
// The items of a parked domain or subdomain list: the API answers with a bare array.
|
|
689
|
+
domainItems(response) {
|
|
690
|
+
if (Array.isArray(response)) {
|
|
691
|
+
return response;
|
|
692
|
+
}
|
|
693
|
+
return response && Array.isArray(response.data) ? response.data : [];
|
|
694
|
+
}
|
|
695
|
+
|
|
680
696
|
hosting_deploy_types = ['static', 'nodejs', 'wordpress-site', 'wordpress-plugin', 'wordpress-theme'];
|
|
681
697
|
|
|
682
698
|
// A package.json that depends on one of these is an app with a server, not dev tooling.
|
|
@@ -1548,6 +1564,143 @@ class MCPServer {
|
|
|
1548
1564
|
return { domain, cleared: scope, directory, response };
|
|
1549
1565
|
}
|
|
1550
1566
|
|
|
1567
|
+
// A 404 means the domain is not a website on the account, which fails the whole call; any other
|
|
1568
|
+
// failure only fails its own list.
|
|
1569
|
+
async hosting_websitesListDomains_section(request, pick) {
|
|
1570
|
+
try {
|
|
1571
|
+
return this.domainItems(await request).map(pick);
|
|
1572
|
+
} catch (error) {
|
|
1573
|
+
if (error instanceof ApiExecutionError && error.status === 404) {
|
|
1574
|
+
throw error;
|
|
1575
|
+
}
|
|
1576
|
+
return { error: this.formatToolError(error) };
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
async handleHostingWebsitesListDomains(params) {
|
|
1581
|
+
const { domain: requestedDomain } = params;
|
|
1582
|
+
|
|
1583
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1584
|
+
throw new Error('domain is required and must be a string');
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1588
|
+
const target = { username, domain };
|
|
1589
|
+
|
|
1590
|
+
const [parked, subdomains] = await Promise.all([
|
|
1591
|
+
this.hosting_websitesListDomains_section(this.callOperation('hosting_domains_list-website-parked', target), (item) => ({
|
|
1592
|
+
domain: item.domain,
|
|
1593
|
+
type: item.type,
|
|
1594
|
+
root_directory: item.root_directory,
|
|
1595
|
+
})),
|
|
1596
|
+
this.hosting_websitesListDomains_section(this.callOperation('hosting_domains_list-website-subdomains', target), (item) => ({
|
|
1597
|
+
domain: item.domain,
|
|
1598
|
+
subdomain: item.subdomain,
|
|
1599
|
+
root_directory: item.root_directory,
|
|
1600
|
+
})),
|
|
1601
|
+
]);
|
|
1602
|
+
|
|
1603
|
+
return { domain, parked, subdomains };
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
async handleHostingWebsitesAddDomain(params) {
|
|
1607
|
+
const { domain: requestedDomain, type, name } = params;
|
|
1608
|
+
// Models send null for fields they leave unset.
|
|
1609
|
+
const directory = params.directory ?? null;
|
|
1610
|
+
const usePublicDirectory = params.usePublicDirectory ?? null;
|
|
1611
|
+
|
|
1612
|
+
if (type !== 'parked' && type !== 'subdomain') {
|
|
1613
|
+
throw new Error('type must be parked or subdomain');
|
|
1614
|
+
}
|
|
1615
|
+
if (!name || typeof name !== 'string') {
|
|
1616
|
+
throw new Error('name is required and must be a string');
|
|
1617
|
+
}
|
|
1618
|
+
if (directory !== null && (typeof directory !== 'string' || directory === '')) {
|
|
1619
|
+
throw new Error('directory must be a non-empty string when provided');
|
|
1620
|
+
}
|
|
1621
|
+
if (usePublicDirectory !== null && typeof usePublicDirectory !== 'boolean') {
|
|
1622
|
+
throw new Error('usePublicDirectory must be a boolean');
|
|
1623
|
+
}
|
|
1624
|
+
if (type === 'parked' && (directory !== null || usePublicDirectory !== null)) {
|
|
1625
|
+
throw new Error('directory and usePublicDirectory apply only to type subdomain');
|
|
1626
|
+
}
|
|
1627
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1628
|
+
throw new Error('domain is required and must be a string');
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
let prefix = '';
|
|
1632
|
+
if (type === 'subdomain') {
|
|
1633
|
+
const suffix = '.' + requestedDomain.toLowerCase();
|
|
1634
|
+
prefix = name.toLowerCase().endsWith(suffix) ? name.slice(0, -suffix.length) : name;
|
|
1635
|
+
if (prefix === '' || (prefix === name && name.includes('.'))) {
|
|
1636
|
+
throw new Error('name must be a subdomain prefix (blog) or a name under ' + requestedDomain + ' (blog.' + requestedDomain + ')');
|
|
1637
|
+
}
|
|
1638
|
+
if (prefix.toLowerCase() === 'www') {
|
|
1639
|
+
throw new Error('www cannot be added as a subdomain: it already belongs to ' + requestedDomain);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1644
|
+
|
|
1645
|
+
if (type === 'parked') {
|
|
1646
|
+
const response = await this.callOperation('hosting_domains_create-website-parked', { username, domain, parked_domain: name });
|
|
1647
|
+
return { domain, type, name, response };
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const response = await this.callOperation('hosting_domains_create-website-subdomain', {
|
|
1651
|
+
username,
|
|
1652
|
+
domain,
|
|
1653
|
+
subdomain: prefix,
|
|
1654
|
+
...(directory !== null ? { directory } : {}),
|
|
1655
|
+
...(usePublicDirectory !== null ? { is_using_public_directory: usePublicDirectory } : {}),
|
|
1656
|
+
});
|
|
1657
|
+
return { domain, type, name: prefix + '.' + domain, response };
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
async handleHostingWebsitesRemoveDomain(params) {
|
|
1661
|
+
const { domain: requestedDomain, name } = params;
|
|
1662
|
+
|
|
1663
|
+
if (!name || typeof name !== 'string') {
|
|
1664
|
+
throw new Error('name is required and must be a string');
|
|
1665
|
+
}
|
|
1666
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1667
|
+
throw new Error('domain is required and must be a string');
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1671
|
+
const target = { username, domain };
|
|
1672
|
+
|
|
1673
|
+
const [parkedResponse, subdomainsResponse] = await Promise.all([
|
|
1674
|
+
this.callOperation('hosting_domains_list-website-parked', target),
|
|
1675
|
+
this.callOperation('hosting_domains_list-website-subdomains', target),
|
|
1676
|
+
]);
|
|
1677
|
+
const parkedDomains = this.domainItems(parkedResponse);
|
|
1678
|
+
const subdomains = this.domainItems(subdomainsResponse);
|
|
1679
|
+
const wanted = name.toLowerCase();
|
|
1680
|
+
|
|
1681
|
+
const parked = parkedDomains.find((item) => typeof item.domain === 'string' && item.domain.toLowerCase() === wanted);
|
|
1682
|
+
if (parked) {
|
|
1683
|
+
const response = await this.callOperation('hosting_domains_delete-website-parked', { ...target, parkedDomain: parked.domain });
|
|
1684
|
+
return { domain, type: 'parked', name: parked.domain, response };
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const subdomain = subdomains.find((item) => (typeof item.domain === 'string' && item.domain.toLowerCase() === wanted)
|
|
1688
|
+
|| (typeof item.subdomain === 'string' && item.subdomain.toLowerCase() === wanted));
|
|
1689
|
+
if (subdomain) {
|
|
1690
|
+
const response = await this.callOperation('hosting_domains_delete-website-subdomain', { ...target, subdomain: subdomain.subdomain });
|
|
1691
|
+
return { domain, type: 'subdomain', name: subdomain.domain, response };
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
const listed = (items) => items.map((item) => item.domain).filter(Boolean).join(', ') || 'none';
|
|
1695
|
+
throw new Error(name + ' is not a parked domain or subdomain of ' + domain + '. Parked domains: ' + listed(parkedDomains) + '. Subdomains: ' + listed(subdomains) + '.');
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
async handleHostingWebsitesStartSetup(params) {
|
|
1699
|
+
// Models send null for fields they leave unset; the setup endpoint rejects some of them.
|
|
1700
|
+
const forwarded = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== null && value !== undefined));
|
|
1701
|
+
return this.callOperation('hosting_websites_create', forwarded);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1551
1704
|
hosting_importWordpressWebsite_validateArchiveFormat(filePath) {
|
|
1552
1705
|
const validExtensions = ['zip', 'tar', 'tar.gz', 'tgz', '7z', 'gz', 'gzip'];
|
|
1553
1706
|
const fileName = path.basename(filePath).toLowerCase();
|
package/src/core/runtime.ts
CHANGED
|
@@ -94,7 +94,7 @@ interface Skill { uri: string; frontmatter: Record<string, unknown>; resources:
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* MCP Server for Hostinger API
|
|
97
|
-
* Generated from OpenAPI spec version 2.6.
|
|
97
|
+
* Generated from OpenAPI spec version 2.6.2
|
|
98
98
|
*/
|
|
99
99
|
class MCPServer {
|
|
100
100
|
private readonly name: string;
|
|
@@ -336,6 +336,14 @@ class MCPServer {
|
|
|
336
336
|
return await this.handleHostingWebsitesUpdateSettings(params);
|
|
337
337
|
case 'hosting_cache_clear':
|
|
338
338
|
return await this.handleHostingCacheClear(params);
|
|
339
|
+
case 'hosting_websites_list-domains':
|
|
340
|
+
return await this.handleHostingWebsitesListDomains(params);
|
|
341
|
+
case 'hosting_websites_add-domain':
|
|
342
|
+
return await this.handleHostingWebsitesAddDomain(params);
|
|
343
|
+
case 'hosting_websites_remove-domain':
|
|
344
|
+
return await this.handleHostingWebsitesRemoveDomain(params);
|
|
345
|
+
case 'hosting_websites_start-setup':
|
|
346
|
+
return await this.handleHostingWebsitesStartSetup(params);
|
|
339
347
|
case 'hosting_import-wordpress-website':
|
|
340
348
|
return await this.handleWordpressWebsiteImport(params);
|
|
341
349
|
case 'hosting_deploy-wordpress-plugin':
|
|
@@ -715,6 +723,14 @@ class MCPServer {
|
|
|
715
723
|
throw new Error('No website found for domain: ' + domain);
|
|
716
724
|
}
|
|
717
725
|
|
|
726
|
+
// The items of a parked domain or subdomain list: the API answers with a bare array.
|
|
727
|
+
private domainItems(response: any): any[] {
|
|
728
|
+
if (Array.isArray(response)) {
|
|
729
|
+
return response;
|
|
730
|
+
}
|
|
731
|
+
return response && Array.isArray(response.data) ? response.data : [];
|
|
732
|
+
}
|
|
733
|
+
|
|
718
734
|
private hosting_deploy_types = ['static', 'nodejs', 'wordpress-site', 'wordpress-plugin', 'wordpress-theme'];
|
|
719
735
|
|
|
720
736
|
// A package.json that depends on one of these is an app with a server, not dev tooling.
|
|
@@ -1586,6 +1602,143 @@ class MCPServer {
|
|
|
1586
1602
|
return { domain, cleared: scope, directory, response };
|
|
1587
1603
|
}
|
|
1588
1604
|
|
|
1605
|
+
// A 404 means the domain is not a website on the account, which fails the whole call; any other
|
|
1606
|
+
// failure only fails its own list.
|
|
1607
|
+
private async hosting_websitesListDomains_section(request: Promise<any>, pick: (item: any) => any): Promise<any> {
|
|
1608
|
+
try {
|
|
1609
|
+
return this.domainItems(await request).map(pick);
|
|
1610
|
+
} catch (error) {
|
|
1611
|
+
if (error instanceof ApiExecutionError && error.status === 404) {
|
|
1612
|
+
throw error;
|
|
1613
|
+
}
|
|
1614
|
+
return { error: this.formatToolError(error) };
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
private async handleHostingWebsitesListDomains(params: Record<string, any>): Promise<any> {
|
|
1619
|
+
const { domain: requestedDomain } = params;
|
|
1620
|
+
|
|
1621
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1622
|
+
throw new Error('domain is required and must be a string');
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1626
|
+
const target = { username, domain };
|
|
1627
|
+
|
|
1628
|
+
const [parked, subdomains] = await Promise.all([
|
|
1629
|
+
this.hosting_websitesListDomains_section(this.callOperation('hosting_domains_list-website-parked', target), (item: any) => ({
|
|
1630
|
+
domain: item.domain,
|
|
1631
|
+
type: item.type,
|
|
1632
|
+
root_directory: item.root_directory,
|
|
1633
|
+
})),
|
|
1634
|
+
this.hosting_websitesListDomains_section(this.callOperation('hosting_domains_list-website-subdomains', target), (item: any) => ({
|
|
1635
|
+
domain: item.domain,
|
|
1636
|
+
subdomain: item.subdomain,
|
|
1637
|
+
root_directory: item.root_directory,
|
|
1638
|
+
})),
|
|
1639
|
+
]);
|
|
1640
|
+
|
|
1641
|
+
return { domain, parked, subdomains };
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
private async handleHostingWebsitesAddDomain(params: Record<string, any>): Promise<any> {
|
|
1645
|
+
const { domain: requestedDomain, type, name } = params;
|
|
1646
|
+
// Models send null for fields they leave unset.
|
|
1647
|
+
const directory = params.directory ?? null;
|
|
1648
|
+
const usePublicDirectory = params.usePublicDirectory ?? null;
|
|
1649
|
+
|
|
1650
|
+
if (type !== 'parked' && type !== 'subdomain') {
|
|
1651
|
+
throw new Error('type must be parked or subdomain');
|
|
1652
|
+
}
|
|
1653
|
+
if (!name || typeof name !== 'string') {
|
|
1654
|
+
throw new Error('name is required and must be a string');
|
|
1655
|
+
}
|
|
1656
|
+
if (directory !== null && (typeof directory !== 'string' || directory === '')) {
|
|
1657
|
+
throw new Error('directory must be a non-empty string when provided');
|
|
1658
|
+
}
|
|
1659
|
+
if (usePublicDirectory !== null && typeof usePublicDirectory !== 'boolean') {
|
|
1660
|
+
throw new Error('usePublicDirectory must be a boolean');
|
|
1661
|
+
}
|
|
1662
|
+
if (type === 'parked' && (directory !== null || usePublicDirectory !== null)) {
|
|
1663
|
+
throw new Error('directory and usePublicDirectory apply only to type subdomain');
|
|
1664
|
+
}
|
|
1665
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1666
|
+
throw new Error('domain is required and must be a string');
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
let prefix = '';
|
|
1670
|
+
if (type === 'subdomain') {
|
|
1671
|
+
const suffix = '.' + requestedDomain.toLowerCase();
|
|
1672
|
+
prefix = name.toLowerCase().endsWith(suffix) ? name.slice(0, -suffix.length) : name;
|
|
1673
|
+
if (prefix === '' || (prefix === name && name.includes('.'))) {
|
|
1674
|
+
throw new Error('name must be a subdomain prefix (blog) or a name under ' + requestedDomain + ' (blog.' + requestedDomain + ')');
|
|
1675
|
+
}
|
|
1676
|
+
if (prefix.toLowerCase() === 'www') {
|
|
1677
|
+
throw new Error('www cannot be added as a subdomain: it already belongs to ' + requestedDomain);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1682
|
+
|
|
1683
|
+
if (type === 'parked') {
|
|
1684
|
+
const response = await this.callOperation('hosting_domains_create-website-parked', { username, domain, parked_domain: name });
|
|
1685
|
+
return { domain, type, name, response };
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
const response = await this.callOperation('hosting_domains_create-website-subdomain', {
|
|
1689
|
+
username,
|
|
1690
|
+
domain,
|
|
1691
|
+
subdomain: prefix,
|
|
1692
|
+
...(directory !== null ? { directory } : {}),
|
|
1693
|
+
...(usePublicDirectory !== null ? { is_using_public_directory: usePublicDirectory } : {}),
|
|
1694
|
+
});
|
|
1695
|
+
return { domain, type, name: prefix + '.' + domain, response };
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
private async handleHostingWebsitesRemoveDomain(params: Record<string, any>): Promise<any> {
|
|
1699
|
+
const { domain: requestedDomain, name } = params;
|
|
1700
|
+
|
|
1701
|
+
if (!name || typeof name !== 'string') {
|
|
1702
|
+
throw new Error('name is required and must be a string');
|
|
1703
|
+
}
|
|
1704
|
+
if (!requestedDomain || typeof requestedDomain !== 'string') {
|
|
1705
|
+
throw new Error('domain is required and must be a string');
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
const { username, domain } = await this.findWebsite(requestedDomain);
|
|
1709
|
+
const target = { username, domain };
|
|
1710
|
+
|
|
1711
|
+
const [parkedResponse, subdomainsResponse] = await Promise.all([
|
|
1712
|
+
this.callOperation('hosting_domains_list-website-parked', target),
|
|
1713
|
+
this.callOperation('hosting_domains_list-website-subdomains', target),
|
|
1714
|
+
]);
|
|
1715
|
+
const parkedDomains = this.domainItems(parkedResponse);
|
|
1716
|
+
const subdomains = this.domainItems(subdomainsResponse);
|
|
1717
|
+
const wanted = name.toLowerCase();
|
|
1718
|
+
|
|
1719
|
+
const parked = parkedDomains.find((item: any) => typeof item.domain === 'string' && item.domain.toLowerCase() === wanted);
|
|
1720
|
+
if (parked) {
|
|
1721
|
+
const response = await this.callOperation('hosting_domains_delete-website-parked', { ...target, parkedDomain: parked.domain });
|
|
1722
|
+
return { domain, type: 'parked', name: parked.domain, response };
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const subdomain = subdomains.find((item: any) => (typeof item.domain === 'string' && item.domain.toLowerCase() === wanted)
|
|
1726
|
+
|| (typeof item.subdomain === 'string' && item.subdomain.toLowerCase() === wanted));
|
|
1727
|
+
if (subdomain) {
|
|
1728
|
+
const response = await this.callOperation('hosting_domains_delete-website-subdomain', { ...target, subdomain: subdomain.subdomain });
|
|
1729
|
+
return { domain, type: 'subdomain', name: subdomain.domain, response };
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
const listed = (items: any[]): string => items.map((item: any) => item.domain).filter(Boolean).join(', ') || 'none';
|
|
1733
|
+
throw new Error(name + ' is not a parked domain or subdomain of ' + domain + '. Parked domains: ' + listed(parkedDomains) + '. Subdomains: ' + listed(subdomains) + '.');
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
private async handleHostingWebsitesStartSetup(params: Record<string, any>): Promise<any> {
|
|
1737
|
+
// Models send null for fields they leave unset; the setup endpoint rejects some of them.
|
|
1738
|
+
const forwarded = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== null && value !== undefined));
|
|
1739
|
+
return this.callOperation('hosting_websites_create', forwarded);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1589
1742
|
private hosting_importWordpressWebsite_validateArchiveFormat(filePath: string): boolean {
|
|
1590
1743
|
const validExtensions = ['zip', 'tar', 'tar.gz', 'tgz', '7z', 'gz', 'gzip'];
|
|
1591
1744
|
const fileName = path.basename(filePath).toLowerCase();
|