pulsemcp-cms-admin-mcp-server 0.3.2 → 0.4.0
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/README.md +26 -16
- package/build/shared/src/pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js +58 -0
- package/build/shared/src/pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js +58 -0
- package/build/shared/src/pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js +62 -0
- package/build/shared/src/pulsemcp-admin-client/lib/get-official-mirror-queue-item.js +71 -0
- package/build/shared/src/pulsemcp-admin-client/lib/get-official-mirror-queue-items.js +73 -0
- package/build/shared/src/pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js +54 -0
- package/build/shared/src/pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js +62 -0
- package/build/shared/src/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +227 -0
- package/build/shared/src/server.js +34 -3
- package/build/shared/src/tools/add-official-mirror-to-regular-queue.js +82 -0
- package/build/shared/src/tools/approve-official-mirror-queue-item-without-modifying.js +76 -0
- package/build/shared/src/tools/approve-official-mirror-queue-item.js +85 -0
- package/build/shared/src/tools/get-official-mirror-queue-item.js +165 -0
- package/build/shared/src/tools/get-official-mirror-queue-items.js +130 -0
- package/build/shared/src/tools/reject-official-mirror-queue-item.js +71 -0
- package/build/shared/src/tools/send-mcp-implementation-posting-notification.js +44 -11
- package/build/shared/src/tools/unlink-official-mirror-queue-item.js +79 -0
- package/build/shared/src/tools.js +33 -2
- package/package.json +1 -1
- package/shared/pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/add-official-mirror-to-regular-queue.js +58 -0
- package/shared/pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/approve-official-mirror-queue-item-without-modifying.js +58 -0
- package/shared/pulsemcp-admin-client/lib/approve-official-mirror-queue-item.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/approve-official-mirror-queue-item.js +62 -0
- package/shared/pulsemcp-admin-client/lib/get-official-mirror-queue-item.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/get-official-mirror-queue-item.js +71 -0
- package/shared/pulsemcp-admin-client/lib/get-official-mirror-queue-items.d.ts +8 -0
- package/shared/pulsemcp-admin-client/lib/get-official-mirror-queue-items.js +73 -0
- package/shared/pulsemcp-admin-client/lib/reject-official-mirror-queue-item.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/reject-official-mirror-queue-item.js +54 -0
- package/shared/pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.d.ts +3 -0
- package/shared/pulsemcp-admin-client/lib/unlink-official-mirror-queue-item.js +62 -0
- package/shared/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.d.ts +12 -1
- package/shared/pulsemcp-admin-client/pulsemcp-admin-client.integration-mock.js +227 -0
- package/shared/server.d.ts +26 -2
- package/shared/server.js +34 -3
- package/shared/tools/add-official-mirror-to-regular-queue.d.ts +30 -0
- package/shared/tools/add-official-mirror-to-regular-queue.js +82 -0
- package/shared/tools/approve-official-mirror-queue-item-without-modifying.d.ts +30 -0
- package/shared/tools/approve-official-mirror-queue-item-without-modifying.js +76 -0
- package/shared/tools/approve-official-mirror-queue-item.d.ts +34 -0
- package/shared/tools/approve-official-mirror-queue-item.js +85 -0
- package/shared/tools/get-official-mirror-queue-item.d.ts +30 -0
- package/shared/tools/get-official-mirror-queue-item.js +165 -0
- package/shared/tools/get-official-mirror-queue-items.d.ts +45 -0
- package/shared/tools/get-official-mirror-queue-items.js +130 -0
- package/shared/tools/reject-official-mirror-queue-item.d.ts +30 -0
- package/shared/tools/reject-official-mirror-queue-item.js +71 -0
- package/shared/tools/send-mcp-implementation-posting-notification.d.ts +4 -0
- package/shared/tools/send-mcp-implementation-posting-notification.js +44 -11
- package/shared/tools/unlink-official-mirror-queue-item.d.ts +30 -0
- package/shared/tools/unlink-official-mirror-queue-item.js +79 -0
- package/shared/tools.d.ts +5 -1
- package/shared/tools.js +33 -2
- package/shared/types.d.ts +75 -0
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ This is an MCP ([Model Context Protocol](https://modelcontextprotocol.io/)) Serv
|
|
|
32
32
|
|
|
33
33
|
**MCP Implementation Search**: Search for MCP servers and clients in the PulseMCP registry.
|
|
34
34
|
|
|
35
|
-
**Toolgroups**: Enable/disable tool groups (newsletter, server_queue_readonly, server_queue_all) via environment variable.
|
|
35
|
+
**Toolgroups**: Enable/disable tool groups (newsletter, server_queue_readonly, server_queue_all, official_queue_readonly, official_queue_all) via environment variable.
|
|
36
36
|
|
|
37
37
|
**Draft Control**: Manage draft posts before publishing to the newsletter.
|
|
38
38
|
|
|
@@ -40,26 +40,36 @@ This is an MCP ([Model Context Protocol](https://modelcontextprotocol.io/)) Serv
|
|
|
40
40
|
|
|
41
41
|
This server is built and tested on macOS with Claude Desktop. It should work with other MCP clients as well.
|
|
42
42
|
|
|
43
|
-
| Tool Name
|
|
44
|
-
|
|
|
45
|
-
| `get_newsletter_posts`
|
|
46
|
-
| `get_newsletter_post`
|
|
47
|
-
| `draft_newsletter_post`
|
|
48
|
-
| `update_newsletter_post`
|
|
49
|
-
| `upload_image`
|
|
50
|
-
| `get_authors`
|
|
51
|
-
| `search_mcp_implementations`
|
|
52
|
-
| `get_draft_mcp_implementations`
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
43
|
+
| Tool Name | Tool Group | Description |
|
|
44
|
+
| ------------------------------------------------------ | ----------------------- | ---------------------------------------------------------------------------- |
|
|
45
|
+
| `get_newsletter_posts` | newsletter | List newsletter posts with search, sorting, and pagination options. |
|
|
46
|
+
| `get_newsletter_post` | newsletter | Retrieve a specific newsletter post by its unique slug. |
|
|
47
|
+
| `draft_newsletter_post` | newsletter | Create a new draft newsletter post with title, body, and metadata. |
|
|
48
|
+
| `update_newsletter_post` | newsletter | Update an existing newsletter post's content and metadata (except status). |
|
|
49
|
+
| `upload_image` | newsletter | Upload an image and attach it to a specific newsletter post. |
|
|
50
|
+
| `get_authors` | newsletter | Get a list of authors with optional search and pagination. |
|
|
51
|
+
| `search_mcp_implementations` | server_queue_readonly | Search for MCP servers and clients in the PulseMCP registry. |
|
|
52
|
+
| `get_draft_mcp_implementations` | server_queue_readonly | Retrieve paginated list of draft MCP implementations needing review. |
|
|
53
|
+
| `find_providers` | server_queue_readonly | Search for providers by ID, name, URL, or slug. |
|
|
54
|
+
| `save_mcp_implementation` | server_queue_all | Update an MCP implementation (replicates Admin panel "Save Changes" button). |
|
|
55
|
+
| `send_mcp_implementation_posting_notification` | server_queue_all | Send email notification when MCP implementation goes live. |
|
|
56
|
+
| `get_official_mirror_queue_items` | official_queue_readonly | List and filter official mirror queue entries with pagination and search. |
|
|
57
|
+
| `get_official_mirror_queue_item` | official_queue_readonly | Get detailed information about a single official mirror queue entry. |
|
|
58
|
+
| `approve_official_mirror_queue_item` | official_queue_all | Approve a queue entry and link it to an existing MCP server (async). |
|
|
59
|
+
| `approve_official_mirror_queue_item_without_modifying` | official_queue_all | Approve without updating the linked server. |
|
|
60
|
+
| `reject_official_mirror_queue_item` | official_queue_all | Reject a queue entry (async operation). |
|
|
61
|
+
| `add_official_mirror_to_regular_queue` | official_queue_all | Convert a queue entry to a draft MCP implementation (async). |
|
|
62
|
+
| `unlink_official_mirror_queue_item` | official_queue_all | Unlink a queue entry from its linked MCP server. |
|
|
55
63
|
|
|
56
64
|
# Tool Groups
|
|
57
65
|
|
|
58
66
|
This server organizes tools into groups that can be selectively enabled or disabled:
|
|
59
67
|
|
|
60
68
|
- **newsletter** (6 tools): Newsletter management, image uploads, and author retrieval
|
|
61
|
-
- **server_queue_readonly** (
|
|
62
|
-
- **server_queue_all** (
|
|
69
|
+
- **server_queue_readonly** (3 tools): Read-only MCP implementation tools (search, draft retrieval, provider lookup)
|
|
70
|
+
- **server_queue_all** (5 tools): All MCP implementation tools including write operations (search, draft retrieval, provider lookup, update, and email notification)
|
|
71
|
+
- **official_queue_readonly** (2 tools): Read-only official mirror queue tools (list, get details)
|
|
72
|
+
- **official_queue_all** (7 tools): All official mirror queue tools including approve, reject, unlink, and add to regular queue
|
|
63
73
|
|
|
64
74
|
You can control which tool groups are available by setting the `PULSEMCP_ADMIN_ENABLED_TOOLGROUPS` environment variable as a comma-separated list (e.g., `newsletter,server_queue_readonly`). If not set, all tool groups are enabled by default.
|
|
65
75
|
|
|
@@ -184,7 +194,7 @@ Add to your Claude Desktop configuration:
|
|
|
184
194
|
"args": ["/path/to/pulsemcp-cms-admin/local/build/index.js"],
|
|
185
195
|
"env": {
|
|
186
196
|
"PULSEMCP_ADMIN_API_KEY": "your-api-key-here",
|
|
187
|
-
"PULSEMCP_ADMIN_ENABLED_TOOLGROUPS": "newsletter,server_queue_readonly,server_queue_all"
|
|
197
|
+
"PULSEMCP_ADMIN_ENABLED_TOOLGROUPS": "newsletter,server_queue_readonly,server_queue_all,official_queue_readonly,official_queue_all"
|
|
188
198
|
}
|
|
189
199
|
}
|
|
190
200
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
function mapQueueItem(item) {
|
|
2
|
+
return {
|
|
3
|
+
id: item.id,
|
|
4
|
+
name: item.name,
|
|
5
|
+
status: item.status,
|
|
6
|
+
mirrors_count: item.mirrors_count,
|
|
7
|
+
linked_server_slug: item.linked_server_slug,
|
|
8
|
+
linked_server_id: item.linked_server_id,
|
|
9
|
+
latest_mirror: item.latest_mirror
|
|
10
|
+
? {
|
|
11
|
+
id: item.latest_mirror.id,
|
|
12
|
+
name: item.latest_mirror.name,
|
|
13
|
+
version: item.latest_mirror.version,
|
|
14
|
+
description: item.latest_mirror.description,
|
|
15
|
+
github_url: item.latest_mirror.github_url,
|
|
16
|
+
website_url: item.latest_mirror.website_url,
|
|
17
|
+
published_at: item.latest_mirror.published_at,
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
created_at: item.created_at,
|
|
21
|
+
updated_at: item.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function addOfficialMirrorToRegularQueue(apiKey, baseUrl, id) {
|
|
25
|
+
const url = new URL(`/api/official_mirror_queues/${id}/add_to_regular_queue`, baseUrl);
|
|
26
|
+
const response = await fetch(url.toString(), {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'X-API-Key': apiKey,
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
throw new Error('Invalid API key');
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 403) {
|
|
38
|
+
throw new Error('User lacks admin privileges');
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 400) {
|
|
41
|
+
throw new Error('Invalid queue entry ID');
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 404) {
|
|
44
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
45
|
+
}
|
|
46
|
+
if (response.status === 422) {
|
|
47
|
+
const errorData = (await response.json());
|
|
48
|
+
throw new Error(errorData.error || 'Validation failed');
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`Failed to add official mirror to regular queue: ${response.status} ${response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
const data = (await response.json());
|
|
53
|
+
return {
|
|
54
|
+
success: data.success,
|
|
55
|
+
message: data.message,
|
|
56
|
+
queue_item: mapQueueItem(data.queue_item),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
function mapQueueItem(item) {
|
|
2
|
+
return {
|
|
3
|
+
id: item.id,
|
|
4
|
+
name: item.name,
|
|
5
|
+
status: item.status,
|
|
6
|
+
mirrors_count: item.mirrors_count,
|
|
7
|
+
linked_server_slug: item.linked_server_slug,
|
|
8
|
+
linked_server_id: item.linked_server_id,
|
|
9
|
+
latest_mirror: item.latest_mirror
|
|
10
|
+
? {
|
|
11
|
+
id: item.latest_mirror.id,
|
|
12
|
+
name: item.latest_mirror.name,
|
|
13
|
+
version: item.latest_mirror.version,
|
|
14
|
+
description: item.latest_mirror.description,
|
|
15
|
+
github_url: item.latest_mirror.github_url,
|
|
16
|
+
website_url: item.latest_mirror.website_url,
|
|
17
|
+
published_at: item.latest_mirror.published_at,
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
created_at: item.created_at,
|
|
21
|
+
updated_at: item.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function approveOfficialMirrorQueueItemWithoutModifying(apiKey, baseUrl, id) {
|
|
25
|
+
const url = new URL(`/api/official_mirror_queues/${id}/approve_without_modifying`, baseUrl);
|
|
26
|
+
const response = await fetch(url.toString(), {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'X-API-Key': apiKey,
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
throw new Error('Invalid API key');
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 403) {
|
|
38
|
+
throw new Error('User lacks admin privileges');
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 400) {
|
|
41
|
+
throw new Error('Invalid queue entry ID');
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 404) {
|
|
44
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
45
|
+
}
|
|
46
|
+
if (response.status === 422) {
|
|
47
|
+
const errorData = (await response.json());
|
|
48
|
+
throw new Error(errorData.error || 'Validation failed');
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`Failed to approve official mirror queue item: ${response.status} ${response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
const data = (await response.json());
|
|
53
|
+
return {
|
|
54
|
+
success: data.success,
|
|
55
|
+
message: data.message,
|
|
56
|
+
queue_item: mapQueueItem(data.queue_item),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function mapQueueItem(item) {
|
|
2
|
+
return {
|
|
3
|
+
id: item.id,
|
|
4
|
+
name: item.name,
|
|
5
|
+
status: item.status,
|
|
6
|
+
mirrors_count: item.mirrors_count,
|
|
7
|
+
linked_server_slug: item.linked_server_slug,
|
|
8
|
+
linked_server_id: item.linked_server_id,
|
|
9
|
+
latest_mirror: item.latest_mirror
|
|
10
|
+
? {
|
|
11
|
+
id: item.latest_mirror.id,
|
|
12
|
+
name: item.latest_mirror.name,
|
|
13
|
+
version: item.latest_mirror.version,
|
|
14
|
+
description: item.latest_mirror.description,
|
|
15
|
+
github_url: item.latest_mirror.github_url,
|
|
16
|
+
website_url: item.latest_mirror.website_url,
|
|
17
|
+
published_at: item.latest_mirror.published_at,
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
created_at: item.created_at,
|
|
21
|
+
updated_at: item.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function approveOfficialMirrorQueueItem(apiKey, baseUrl, id, mcpServerSlug) {
|
|
25
|
+
const url = new URL(`/api/official_mirror_queues/${id}/approve`, baseUrl);
|
|
26
|
+
const formData = new URLSearchParams();
|
|
27
|
+
formData.append('mcp_server_slug', mcpServerSlug);
|
|
28
|
+
const response = await fetch(url.toString(), {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'X-API-Key': apiKey,
|
|
32
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
33
|
+
Accept: 'application/json',
|
|
34
|
+
},
|
|
35
|
+
body: formData.toString(),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
if (response.status === 401) {
|
|
39
|
+
throw new Error('Invalid API key');
|
|
40
|
+
}
|
|
41
|
+
if (response.status === 403) {
|
|
42
|
+
throw new Error('User lacks admin privileges');
|
|
43
|
+
}
|
|
44
|
+
if (response.status === 400) {
|
|
45
|
+
throw new Error('Invalid queue entry ID');
|
|
46
|
+
}
|
|
47
|
+
if (response.status === 404) {
|
|
48
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
49
|
+
}
|
|
50
|
+
if (response.status === 422) {
|
|
51
|
+
const errorData = (await response.json());
|
|
52
|
+
throw new Error(errorData.error || 'Validation failed');
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Failed to approve official mirror queue item: ${response.status} ${response.statusText}`);
|
|
55
|
+
}
|
|
56
|
+
const data = (await response.json());
|
|
57
|
+
return {
|
|
58
|
+
success: data.success,
|
|
59
|
+
message: data.message,
|
|
60
|
+
queue_item: mapQueueItem(data.queue_item),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function mapMirror(mirror) {
|
|
2
|
+
return {
|
|
3
|
+
id: mirror.id,
|
|
4
|
+
name: mirror.name,
|
|
5
|
+
version: mirror.version,
|
|
6
|
+
official_version_id: mirror.official_version_id,
|
|
7
|
+
description: mirror.description,
|
|
8
|
+
github_url: mirror.github_url,
|
|
9
|
+
website_url: mirror.website_url,
|
|
10
|
+
categories: mirror.categories,
|
|
11
|
+
license: mirror.license,
|
|
12
|
+
remotes: mirror.remotes,
|
|
13
|
+
packages: mirror.packages,
|
|
14
|
+
published_at: mirror.published_at,
|
|
15
|
+
schema_version: mirror.schema_version,
|
|
16
|
+
datetime_ingested: mirror.datetime_ingested,
|
|
17
|
+
created_at: mirror.created_at,
|
|
18
|
+
updated_at: mirror.updated_at,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function mapLinkedServer(server) {
|
|
22
|
+
if (!server)
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
id: server.id,
|
|
26
|
+
slug: server.slug,
|
|
27
|
+
classification: server.classification,
|
|
28
|
+
implementation_language: server.implementation_language,
|
|
29
|
+
provider_name: server.provider_name,
|
|
30
|
+
provider_slug: server.provider_slug,
|
|
31
|
+
implementation_name: server.implementation_name,
|
|
32
|
+
implementation_status: server.implementation_status,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export async function getOfficialMirrorQueueItem(apiKey, baseUrl, id) {
|
|
36
|
+
const url = new URL(`/api/official_mirror_queues/${id}`, baseUrl);
|
|
37
|
+
const response = await fetch(url.toString(), {
|
|
38
|
+
method: 'GET',
|
|
39
|
+
headers: {
|
|
40
|
+
'X-API-Key': apiKey,
|
|
41
|
+
Accept: 'application/json',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
if (response.status === 401) {
|
|
46
|
+
throw new Error('Invalid API key');
|
|
47
|
+
}
|
|
48
|
+
if (response.status === 403) {
|
|
49
|
+
throw new Error('User lacks admin privileges');
|
|
50
|
+
}
|
|
51
|
+
if (response.status === 400) {
|
|
52
|
+
throw new Error('Invalid queue entry ID');
|
|
53
|
+
}
|
|
54
|
+
if (response.status === 404) {
|
|
55
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Failed to fetch official mirror queue item: ${response.status} ${response.statusText}`);
|
|
58
|
+
}
|
|
59
|
+
const data = (await response.json());
|
|
60
|
+
return {
|
|
61
|
+
id: data.id,
|
|
62
|
+
name: data.name,
|
|
63
|
+
status: data.status,
|
|
64
|
+
mirrors_count: data.mirrors_count,
|
|
65
|
+
linked_server: mapLinkedServer(data.linked_server),
|
|
66
|
+
server_linkage_consistent: data.server_linkage_consistent,
|
|
67
|
+
mirrors: data.mirrors.map(mapMirror),
|
|
68
|
+
created_at: data.created_at,
|
|
69
|
+
updated_at: data.updated_at,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function mapMirrorSummary(mirror) {
|
|
2
|
+
if (!mirror)
|
|
3
|
+
return null;
|
|
4
|
+
return {
|
|
5
|
+
id: mirror.id,
|
|
6
|
+
name: mirror.name,
|
|
7
|
+
version: mirror.version,
|
|
8
|
+
description: mirror.description,
|
|
9
|
+
github_url: mirror.github_url,
|
|
10
|
+
website_url: mirror.website_url,
|
|
11
|
+
published_at: mirror.published_at,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function mapQueueItem(item) {
|
|
15
|
+
return {
|
|
16
|
+
id: item.id,
|
|
17
|
+
name: item.name,
|
|
18
|
+
status: item.status,
|
|
19
|
+
mirrors_count: item.mirrors_count,
|
|
20
|
+
linked_server_slug: item.linked_server_slug,
|
|
21
|
+
linked_server_id: item.linked_server_id,
|
|
22
|
+
latest_mirror: mapMirrorSummary(item.latest_mirror),
|
|
23
|
+
created_at: item.created_at,
|
|
24
|
+
updated_at: item.updated_at,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function getOfficialMirrorQueueItems(apiKey, baseUrl, params) {
|
|
28
|
+
const url = new URL('/api/official_mirror_queues', baseUrl);
|
|
29
|
+
// Add query parameters if provided
|
|
30
|
+
if (params?.status) {
|
|
31
|
+
url.searchParams.append('status', params.status);
|
|
32
|
+
}
|
|
33
|
+
if (params?.q) {
|
|
34
|
+
url.searchParams.append('q', params.q);
|
|
35
|
+
}
|
|
36
|
+
if (params?.limit) {
|
|
37
|
+
url.searchParams.append('limit', params.limit.toString());
|
|
38
|
+
}
|
|
39
|
+
if (params?.offset) {
|
|
40
|
+
url.searchParams.append('offset', params.offset.toString());
|
|
41
|
+
}
|
|
42
|
+
const response = await fetch(url.toString(), {
|
|
43
|
+
method: 'GET',
|
|
44
|
+
headers: {
|
|
45
|
+
'X-API-Key': apiKey,
|
|
46
|
+
Accept: 'application/json',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
if (response.status === 401) {
|
|
51
|
+
throw new Error('Invalid API key');
|
|
52
|
+
}
|
|
53
|
+
if (response.status === 403) {
|
|
54
|
+
throw new Error('User lacks admin privileges');
|
|
55
|
+
}
|
|
56
|
+
if (response.status === 422) {
|
|
57
|
+
const errorData = (await response.json());
|
|
58
|
+
throw new Error(errorData.error || 'Validation failed');
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`Failed to fetch official mirror queue items: ${response.status} ${response.statusText}`);
|
|
61
|
+
}
|
|
62
|
+
const data = (await response.json());
|
|
63
|
+
return {
|
|
64
|
+
items: data.data.map(mapQueueItem),
|
|
65
|
+
pagination: {
|
|
66
|
+
current_page: data.meta.current_page,
|
|
67
|
+
total_pages: data.meta.total_pages,
|
|
68
|
+
total_count: data.meta.total_count,
|
|
69
|
+
has_next: data.meta.has_next,
|
|
70
|
+
limit: data.meta.limit,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
function mapQueueItem(item) {
|
|
2
|
+
return {
|
|
3
|
+
id: item.id,
|
|
4
|
+
name: item.name,
|
|
5
|
+
status: item.status,
|
|
6
|
+
mirrors_count: item.mirrors_count,
|
|
7
|
+
linked_server_slug: item.linked_server_slug,
|
|
8
|
+
linked_server_id: item.linked_server_id,
|
|
9
|
+
latest_mirror: item.latest_mirror
|
|
10
|
+
? {
|
|
11
|
+
id: item.latest_mirror.id,
|
|
12
|
+
name: item.latest_mirror.name,
|
|
13
|
+
version: item.latest_mirror.version,
|
|
14
|
+
description: item.latest_mirror.description,
|
|
15
|
+
github_url: item.latest_mirror.github_url,
|
|
16
|
+
website_url: item.latest_mirror.website_url,
|
|
17
|
+
published_at: item.latest_mirror.published_at,
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
created_at: item.created_at,
|
|
21
|
+
updated_at: item.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function rejectOfficialMirrorQueueItem(apiKey, baseUrl, id) {
|
|
25
|
+
const url = new URL(`/api/official_mirror_queues/${id}/reject`, baseUrl);
|
|
26
|
+
const response = await fetch(url.toString(), {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'X-API-Key': apiKey,
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
throw new Error('Invalid API key');
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 403) {
|
|
38
|
+
throw new Error('User lacks admin privileges');
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 400) {
|
|
41
|
+
throw new Error('Invalid queue entry ID');
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 404) {
|
|
44
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`Failed to reject official mirror queue item: ${response.status} ${response.statusText}`);
|
|
47
|
+
}
|
|
48
|
+
const data = (await response.json());
|
|
49
|
+
return {
|
|
50
|
+
success: data.success,
|
|
51
|
+
message: data.message,
|
|
52
|
+
queue_item: mapQueueItem(data.queue_item),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function mapQueueItem(item) {
|
|
2
|
+
return {
|
|
3
|
+
id: item.id,
|
|
4
|
+
name: item.name,
|
|
5
|
+
status: item.status,
|
|
6
|
+
mirrors_count: item.mirrors_count,
|
|
7
|
+
linked_server_slug: item.linked_server_slug,
|
|
8
|
+
linked_server_id: item.linked_server_id,
|
|
9
|
+
latest_mirror: item.latest_mirror
|
|
10
|
+
? {
|
|
11
|
+
id: item.latest_mirror.id,
|
|
12
|
+
name: item.latest_mirror.name,
|
|
13
|
+
version: item.latest_mirror.version,
|
|
14
|
+
description: item.latest_mirror.description,
|
|
15
|
+
github_url: item.latest_mirror.github_url,
|
|
16
|
+
website_url: item.latest_mirror.website_url,
|
|
17
|
+
published_at: item.latest_mirror.published_at,
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
created_at: item.created_at,
|
|
21
|
+
updated_at: item.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function unlinkOfficialMirrorQueueItem(apiKey, baseUrl, id) {
|
|
25
|
+
const url = new URL(`/api/official_mirror_queues/${id}/unlink`, baseUrl);
|
|
26
|
+
const response = await fetch(url.toString(), {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'X-API-Key': apiKey,
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
throw new Error('Invalid API key');
|
|
36
|
+
}
|
|
37
|
+
if (response.status === 403) {
|
|
38
|
+
throw new Error('User lacks admin privileges');
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 400) {
|
|
41
|
+
throw new Error('Invalid queue entry ID');
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 404) {
|
|
44
|
+
throw new Error(`Queue entry not found: ${id}`);
|
|
45
|
+
}
|
|
46
|
+
if (response.status === 422) {
|
|
47
|
+
const errorData = (await response.json());
|
|
48
|
+
throw new Error(errorData.error || 'Validation failed');
|
|
49
|
+
}
|
|
50
|
+
if (response.status === 500) {
|
|
51
|
+
const errorData = (await response.json());
|
|
52
|
+
throw new Error(errorData.error || 'Failed to unlink');
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Failed to unlink official mirror queue item: ${response.status} ${response.statusText}`);
|
|
55
|
+
}
|
|
56
|
+
const data = (await response.json());
|
|
57
|
+
return {
|
|
58
|
+
success: data.success,
|
|
59
|
+
message: data.message,
|
|
60
|
+
queue_item: mapQueueItem(data.queue_item),
|
|
61
|
+
};
|
|
62
|
+
}
|