@elliotding/ai-agent-mcp 0.1.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/dist/api/cached-client.d.ts +48 -0
- package/dist/api/cached-client.d.ts.map +1 -0
- package/dist/api/cached-client.js +126 -0
- package/dist/api/cached-client.js.map +1 -0
- package/dist/api/client.d.ts +213 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +326 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +26 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +36 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +194 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/permissions.d.ts +60 -0
- package/dist/auth/permissions.d.ts.map +1 -0
- package/dist/auth/permissions.js +256 -0
- package/dist/auth/permissions.js.map +1 -0
- package/dist/auth/token-validator.d.ts +52 -0
- package/dist/auth/token-validator.d.ts.map +1 -0
- package/dist/auth/token-validator.js +217 -0
- package/dist/auth/token-validator.js.map +1 -0
- package/dist/cache/cache-manager.d.ts +49 -0
- package/dist/cache/cache-manager.d.ts.map +1 -0
- package/dist/cache/cache-manager.js +191 -0
- package/dist/cache/cache-manager.js.map +1 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +12 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/redis-client.d.ts +45 -0
- package/dist/cache/redis-client.d.ts.map +1 -0
- package/dist/cache/redis-client.js +210 -0
- package/dist/cache/redis-client.js.map +1 -0
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +31 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/index.d.ts +54 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +168 -0
- package/dist/config/index.js.map +1 -0
- package/dist/filesystem/manager.d.ts +45 -0
- package/dist/filesystem/manager.d.ts.map +1 -0
- package/dist/filesystem/manager.js +246 -0
- package/dist/filesystem/manager.js.map +1 -0
- package/dist/git/multi-source-manager.d.ts +62 -0
- package/dist/git/multi-source-manager.d.ts.map +1 -0
- package/dist/git/multi-source-manager.js +293 -0
- package/dist/git/multi-source-manager.js.map +1 -0
- package/dist/git/operations.d.ts +27 -0
- package/dist/git/operations.d.ts.map +1 -0
- package/dist/git/operations.js +83 -0
- package/dist/git/operations.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/monitoring/health.d.ts +35 -0
- package/dist/monitoring/health.d.ts.map +1 -0
- package/dist/monitoring/health.js +105 -0
- package/dist/monitoring/health.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +10 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/loader.d.ts +87 -0
- package/dist/resources/loader.d.ts.map +1 -0
- package/dist/resources/loader.js +452 -0
- package/dist/resources/loader.js.map +1 -0
- package/dist/server/http.d.ts +57 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +336 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +157 -0
- package/dist/server.js.map +1 -0
- package/dist/session/manager.d.ts +91 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +251 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +27 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/manage-subscription.d.ts +43 -0
- package/dist/tools/manage-subscription.d.ts.map +1 -0
- package/dist/tools/manage-subscription.js +268 -0
- package/dist/tools/manage-subscription.js.map +1 -0
- package/dist/tools/registry.d.ts +40 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/search-resources.d.ts +31 -0
- package/dist/tools/search-resources.d.ts.map +1 -0
- package/dist/tools/search-resources.js +154 -0
- package/dist/tools/search-resources.js.map +1 -0
- package/dist/tools/sync-resources.d.ts +41 -0
- package/dist/tools/sync-resources.d.ts.map +1 -0
- package/dist/tools/sync-resources.js +606 -0
- package/dist/tools/sync-resources.js.map +1 -0
- package/dist/tools/uninstall-resource.d.ts +30 -0
- package/dist/tools/uninstall-resource.d.ts.map +1 -0
- package/dist/tools/uninstall-resource.js +259 -0
- package/dist/tools/uninstall-resource.js.map +1 -0
- package/dist/tools/upload-resource.d.ts +77 -0
- package/dist/tools/upload-resource.d.ts.map +1 -0
- package/dist/tools/upload-resource.js +252 -0
- package/dist/tools/upload-resource.js.map +1 -0
- package/dist/transport/sse.d.ts +29 -0
- package/dist/transport/sse.d.ts.map +1 -0
- package/dist/transport/sse.js +271 -0
- package/dist/transport/sse.js.map +1 -0
- package/dist/types/errors.d.ts +60 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +112 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mcp.d.ts +50 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +6 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/resources.d.ts +109 -0
- package/dist/types/resources.d.ts.map +1 -0
- package/dist/types/resources.js +7 -0
- package/dist/types/resources.js.map +1 -0
- package/dist/types/tools.d.ts +147 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +6 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/utils/cursor-paths.d.ts +49 -0
- package/dist/utils/cursor-paths.d.ts.map +1 -0
- package/dist/utils/cursor-paths.js +116 -0
- package/dist/utils/cursor-paths.js.map +1 -0
- package/dist/utils/log-cleaner.d.ts +18 -0
- package/dist/utils/log-cleaner.d.ts.map +1 -0
- package/dist/utils/log-cleaner.js +112 -0
- package/dist/utils/log-cleaner.js.map +1 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +292 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +58 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +214 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +58 -0
- package/src/api/cached-client.ts +144 -0
- package/src/api/client.ts +578 -0
- package/src/auth/index.ts +11 -0
- package/src/auth/middleware.ts +244 -0
- package/src/auth/permissions.ts +317 -0
- package/src/auth/token-validator.ts +294 -0
- package/src/cache/cache-manager.ts +243 -0
- package/src/cache/index.ts +6 -0
- package/src/cache/redis-client.ts +249 -0
- package/src/config/constants.ts +33 -0
- package/src/config/index.ts +228 -0
- package/src/filesystem/manager.ts +235 -0
- package/src/git/multi-source-manager.ts +333 -0
- package/src/git/operations.ts +93 -0
- package/src/index.ts +139 -0
- package/src/monitoring/health.ts +132 -0
- package/src/resources/index.ts +13 -0
- package/src/resources/loader.ts +530 -0
- package/src/server/http.ts +427 -0
- package/src/server.ts +191 -0
- package/src/session/manager.ts +296 -0
- package/src/tools/index.ts +11 -0
- package/src/tools/manage-subscription.ts +332 -0
- package/src/tools/registry.ts +97 -0
- package/src/tools/search-resources.ts +177 -0
- package/src/tools/sync-resources.ts +662 -0
- package/src/tools/uninstall-resource.ts +248 -0
- package/src/tools/upload-resource.ts +258 -0
- package/src/transport/sse.ts +308 -0
- package/src/types/errors.ts +146 -0
- package/src/types/index.ts +7 -0
- package/src/types/mcp.ts +61 -0
- package/src/types/resources.ts +141 -0
- package/src/types/tools.ts +175 -0
- package/src/utils/cursor-paths.ts +83 -0
- package/src/utils/log-cleaner.ts +92 -0
- package/src/utils/logger.ts +333 -0
- package/src/utils/validation.ts +262 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST API Client
|
|
3
|
+
* HTTP client for CSP Resource Server
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios';
|
|
7
|
+
import { config } from '../config';
|
|
8
|
+
import { logger, logApiRequest, logApiError } from '../utils/logger';
|
|
9
|
+
import { createAPIError } from '../types/errors';
|
|
10
|
+
|
|
11
|
+
class APIClient {
|
|
12
|
+
private client: AxiosInstance;
|
|
13
|
+
private readonly maxRetries = 3;
|
|
14
|
+
private readonly retryDelay = 1000; // 1 second
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
this.client = axios.create({
|
|
18
|
+
baseURL: config.csp.apiBaseUrl,
|
|
19
|
+
timeout: config.csp.timeout,
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
'User-Agent': `csp-ai-agent-mcp/0.2.0`,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Request interceptor for authentication and logging
|
|
27
|
+
this.client.interceptors.request.use(
|
|
28
|
+
(requestConfig) => {
|
|
29
|
+
if (config.csp.apiToken) {
|
|
30
|
+
requestConfig.headers.Authorization = `Bearer ${config.csp.apiToken}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Enhanced request logging
|
|
34
|
+
logger.debug(
|
|
35
|
+
{
|
|
36
|
+
type: 'api_request_start',
|
|
37
|
+
method: requestConfig.method?.toUpperCase(),
|
|
38
|
+
url: requestConfig.url,
|
|
39
|
+
params: requestConfig.params,
|
|
40
|
+
data: requestConfig.data ? JSON.stringify(requestConfig.data).substring(0, 500) : undefined,
|
|
41
|
+
headers: this.sanitizeHeaders(requestConfig.headers as Record<string, string>),
|
|
42
|
+
},
|
|
43
|
+
`API Request: ${requestConfig.method?.toUpperCase()} ${requestConfig.url}`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Record start time for duration calculation
|
|
47
|
+
(requestConfig as any).startTime = Date.now();
|
|
48
|
+
|
|
49
|
+
return requestConfig;
|
|
50
|
+
},
|
|
51
|
+
(error) => {
|
|
52
|
+
logger.error({
|
|
53
|
+
type: 'api_request_interceptor_error',
|
|
54
|
+
error: error.message
|
|
55
|
+
}, 'API request interceptor error');
|
|
56
|
+
return Promise.reject(error);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Response interceptor for detailed logging
|
|
61
|
+
this.client.interceptors.response.use(
|
|
62
|
+
(response) => {
|
|
63
|
+
const startTime = (response.config as any).startTime || Date.now();
|
|
64
|
+
const duration = Date.now() - startTime;
|
|
65
|
+
const method = response.config.method?.toUpperCase() || 'UNKNOWN';
|
|
66
|
+
const url = response.config.url || 'unknown';
|
|
67
|
+
|
|
68
|
+
// Enhanced response logging
|
|
69
|
+
logApiRequest(
|
|
70
|
+
method,
|
|
71
|
+
url,
|
|
72
|
+
response.status,
|
|
73
|
+
duration,
|
|
74
|
+
response.config.data,
|
|
75
|
+
response.data,
|
|
76
|
+
response.headers as Record<string, string>
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return response;
|
|
80
|
+
},
|
|
81
|
+
(error: AxiosError) => {
|
|
82
|
+
const startTime = (error.config as any)?.startTime || Date.now();
|
|
83
|
+
const duration = Date.now() - startTime;
|
|
84
|
+
const statusCode = error.response?.status;
|
|
85
|
+
const method = error.config?.method?.toUpperCase() || 'UNKNOWN';
|
|
86
|
+
const url = error.config?.url || 'unknown';
|
|
87
|
+
|
|
88
|
+
// Enhanced error logging
|
|
89
|
+
logApiError(
|
|
90
|
+
method,
|
|
91
|
+
url,
|
|
92
|
+
error,
|
|
93
|
+
error.config?.data,
|
|
94
|
+
statusCode
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Log response details if available
|
|
98
|
+
if (error.response) {
|
|
99
|
+
logger.error(
|
|
100
|
+
{
|
|
101
|
+
type: 'api_response_error',
|
|
102
|
+
method,
|
|
103
|
+
url,
|
|
104
|
+
status: statusCode,
|
|
105
|
+
statusText: error.response.statusText,
|
|
106
|
+
responseData: error.response.data ? JSON.stringify(error.response.data).substring(0, 1000) : undefined,
|
|
107
|
+
duration,
|
|
108
|
+
},
|
|
109
|
+
`API Error Response: ${method} ${url} - ${statusCode}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return Promise.reject(error);
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sanitize headers to hide sensitive information
|
|
120
|
+
*/
|
|
121
|
+
private sanitizeHeaders(headers: Record<string, string>): Record<string, string> {
|
|
122
|
+
const sanitized = { ...headers };
|
|
123
|
+
if (sanitized['Authorization'] || sanitized['authorization']) {
|
|
124
|
+
const key = sanitized['Authorization'] ? 'Authorization' : 'authorization';
|
|
125
|
+
const value = sanitized[key];
|
|
126
|
+
if (value && value.startsWith('Bearer ')) {
|
|
127
|
+
const token = value.substring(7);
|
|
128
|
+
sanitized[key] = `Bearer ${token.substring(0, 10)}...${token.substring(token.length - 10)}`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return sanitized;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Execute request with retry logic
|
|
136
|
+
*/
|
|
137
|
+
private async executeWithRetry<T>(
|
|
138
|
+
requestFn: () => Promise<T>,
|
|
139
|
+
method: string,
|
|
140
|
+
url: string,
|
|
141
|
+
retryCount = 0
|
|
142
|
+
): Promise<T> {
|
|
143
|
+
try {
|
|
144
|
+
return await requestFn();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const isNetworkError =
|
|
147
|
+
error instanceof AxiosError &&
|
|
148
|
+
(!error.response || error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT');
|
|
149
|
+
|
|
150
|
+
if (isNetworkError && retryCount < this.maxRetries) {
|
|
151
|
+
const delay = this.retryDelay * Math.pow(2, retryCount);
|
|
152
|
+
logger.warn(
|
|
153
|
+
{
|
|
154
|
+
method,
|
|
155
|
+
url,
|
|
156
|
+
retryCount: retryCount + 1,
|
|
157
|
+
maxRetries: this.maxRetries,
|
|
158
|
+
delay,
|
|
159
|
+
},
|
|
160
|
+
`API request failed, retrying in ${delay}ms...`
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
164
|
+
return this.executeWithRetry(requestFn, method, url, retryCount + 1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Transform axios error to APIError
|
|
168
|
+
if (error instanceof AxiosError) {
|
|
169
|
+
throw createAPIError(
|
|
170
|
+
method,
|
|
171
|
+
url,
|
|
172
|
+
error,
|
|
173
|
+
error.response?.status,
|
|
174
|
+
retryCount
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* GET request
|
|
184
|
+
*/
|
|
185
|
+
async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
186
|
+
return this.executeWithRetry(
|
|
187
|
+
async () => {
|
|
188
|
+
const response = await this.client.get<T>(url, config);
|
|
189
|
+
return response.data;
|
|
190
|
+
},
|
|
191
|
+
'GET',
|
|
192
|
+
url
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* POST request
|
|
198
|
+
*/
|
|
199
|
+
async post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
|
|
200
|
+
return this.executeWithRetry(
|
|
201
|
+
async () => {
|
|
202
|
+
const response = await this.client.post<T>(url, data, config);
|
|
203
|
+
return response.data;
|
|
204
|
+
},
|
|
205
|
+
'POST',
|
|
206
|
+
url
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* PUT request
|
|
212
|
+
*/
|
|
213
|
+
async put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
|
|
214
|
+
return this.executeWithRetry(
|
|
215
|
+
async () => {
|
|
216
|
+
const response = await this.client.put<T>(url, data, config);
|
|
217
|
+
return response.data;
|
|
218
|
+
},
|
|
219
|
+
'PUT',
|
|
220
|
+
url
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* DELETE request
|
|
226
|
+
*/
|
|
227
|
+
async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
228
|
+
return this.executeWithRetry(
|
|
229
|
+
async () => {
|
|
230
|
+
const response = await this.client.delete<T>(url, config);
|
|
231
|
+
return response.data;
|
|
232
|
+
},
|
|
233
|
+
'DELETE',
|
|
234
|
+
url
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//===========================================
|
|
239
|
+
// CSP Resource Server API Endpoints
|
|
240
|
+
//===========================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get subscription list
|
|
244
|
+
*/
|
|
245
|
+
async getSubscriptions(params?: {
|
|
246
|
+
scope?: 'general' | 'team' | 'user' | 'all';
|
|
247
|
+
types?: string[];
|
|
248
|
+
detail?: boolean; // Added: include detailed metadata
|
|
249
|
+
}): Promise<{
|
|
250
|
+
total: number;
|
|
251
|
+
subscriptions: Array<{
|
|
252
|
+
id: string;
|
|
253
|
+
name: string;
|
|
254
|
+
type: string;
|
|
255
|
+
team: string;
|
|
256
|
+
subscribed_at: string;
|
|
257
|
+
auto_sync: boolean;
|
|
258
|
+
resource: {
|
|
259
|
+
version: string;
|
|
260
|
+
hash: string;
|
|
261
|
+
download_url: string;
|
|
262
|
+
};
|
|
263
|
+
}>;
|
|
264
|
+
}> {
|
|
265
|
+
const response = await this.get<{
|
|
266
|
+
code: number;
|
|
267
|
+
result: string;
|
|
268
|
+
data: {
|
|
269
|
+
total: number;
|
|
270
|
+
subscriptions: Array<{
|
|
271
|
+
id: string;
|
|
272
|
+
name: string;
|
|
273
|
+
type: string;
|
|
274
|
+
team: string;
|
|
275
|
+
subscribed_at: string;
|
|
276
|
+
auto_sync: boolean;
|
|
277
|
+
resource: {
|
|
278
|
+
version: string;
|
|
279
|
+
hash: string;
|
|
280
|
+
download_url: string;
|
|
281
|
+
};
|
|
282
|
+
}>;
|
|
283
|
+
};
|
|
284
|
+
}>('/csp/api/resources/subscriptions', { params });
|
|
285
|
+
|
|
286
|
+
// Extract data from CSP API response format
|
|
287
|
+
if (!response.data) {
|
|
288
|
+
throw new Error('Invalid API response: missing data field');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return response.data;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Subscribe to resource
|
|
296
|
+
*/
|
|
297
|
+
async subscribe(
|
|
298
|
+
resourceIds: string[],
|
|
299
|
+
autoSync = true,
|
|
300
|
+
scope?: 'general' | 'team' | 'user' // Added: subscription scope
|
|
301
|
+
): Promise<{
|
|
302
|
+
success: boolean;
|
|
303
|
+
subscriptions: Array<{
|
|
304
|
+
id: string;
|
|
305
|
+
name: string;
|
|
306
|
+
type: string;
|
|
307
|
+
subscribed_at: string;
|
|
308
|
+
}>;
|
|
309
|
+
}> {
|
|
310
|
+
const response = await this.post<{
|
|
311
|
+
code: number;
|
|
312
|
+
result: string;
|
|
313
|
+
data: {
|
|
314
|
+
success?: boolean;
|
|
315
|
+
subscriptions: Array<{
|
|
316
|
+
id: string;
|
|
317
|
+
name: string;
|
|
318
|
+
type: string;
|
|
319
|
+
subscribed_at: string;
|
|
320
|
+
}>;
|
|
321
|
+
};
|
|
322
|
+
}>('/csp/api/resources/subscriptions/add', {
|
|
323
|
+
resource_ids: resourceIds,
|
|
324
|
+
auto_sync: autoSync,
|
|
325
|
+
scope,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
if (!response.data) {
|
|
329
|
+
throw new Error('Invalid API response: missing data field');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
success: true,
|
|
334
|
+
subscriptions: response.data.subscriptions
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Unsubscribe from resource
|
|
340
|
+
*/
|
|
341
|
+
async unsubscribe(resourceIds: string | string[]): Promise<void> {
|
|
342
|
+
// Support batch unsubscribe
|
|
343
|
+
const ids = Array.isArray(resourceIds) ? resourceIds : [resourceIds];
|
|
344
|
+
const response = await this.delete<{
|
|
345
|
+
code: number;
|
|
346
|
+
result: string;
|
|
347
|
+
data: { removed_count: number };
|
|
348
|
+
}>('/csp/api/resources/subscriptions/remove', {
|
|
349
|
+
data: { resource_ids: ids }
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Just validate response, no need to return anything
|
|
353
|
+
if (!response.data) {
|
|
354
|
+
throw new Error('Invalid API response: missing data field');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Search resources
|
|
360
|
+
*/
|
|
361
|
+
async searchResources(params: {
|
|
362
|
+
keyword: string;
|
|
363
|
+
team?: string;
|
|
364
|
+
type?: string;
|
|
365
|
+
detail?: boolean; // Added: include detailed metadata
|
|
366
|
+
page?: number; // Added: pagination
|
|
367
|
+
page_size?: number; // Added: page size
|
|
368
|
+
}): Promise<{
|
|
369
|
+
total: number;
|
|
370
|
+
page?: number;
|
|
371
|
+
page_size?: number;
|
|
372
|
+
results: Array<{
|
|
373
|
+
id: string;
|
|
374
|
+
name: string;
|
|
375
|
+
type: string;
|
|
376
|
+
team: string;
|
|
377
|
+
version: string;
|
|
378
|
+
description: string;
|
|
379
|
+
score: number;
|
|
380
|
+
is_subscribed: boolean;
|
|
381
|
+
metadata?: {
|
|
382
|
+
module: string;
|
|
383
|
+
tags: string[];
|
|
384
|
+
author: string;
|
|
385
|
+
created_at: string;
|
|
386
|
+
updated_at: string;
|
|
387
|
+
downloads: number;
|
|
388
|
+
};
|
|
389
|
+
}>;
|
|
390
|
+
}> {
|
|
391
|
+
const response = await this.get<{
|
|
392
|
+
code: number;
|
|
393
|
+
result: string;
|
|
394
|
+
data: {
|
|
395
|
+
total: number;
|
|
396
|
+
page?: number;
|
|
397
|
+
page_size?: number;
|
|
398
|
+
results: Array<{
|
|
399
|
+
id: string;
|
|
400
|
+
name: string;
|
|
401
|
+
type: string;
|
|
402
|
+
team: string;
|
|
403
|
+
version: string;
|
|
404
|
+
description: string;
|
|
405
|
+
score?: number;
|
|
406
|
+
is_subscribed?: boolean;
|
|
407
|
+
download_url?: string;
|
|
408
|
+
metadata?: {
|
|
409
|
+
module: string;
|
|
410
|
+
tags: string[];
|
|
411
|
+
author: string;
|
|
412
|
+
created_at: string;
|
|
413
|
+
updated_at: string;
|
|
414
|
+
downloads: number;
|
|
415
|
+
};
|
|
416
|
+
}>;
|
|
417
|
+
};
|
|
418
|
+
}>('/csp/api/resources/search', { params });
|
|
419
|
+
|
|
420
|
+
// Extract data from CSP API response format
|
|
421
|
+
if (!response.data) {
|
|
422
|
+
throw new Error('Invalid API response: missing data field');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
total: response.data.total,
|
|
427
|
+
page: response.data.page,
|
|
428
|
+
page_size: response.data.page_size,
|
|
429
|
+
results: response.data.results.map(r => ({
|
|
430
|
+
...r,
|
|
431
|
+
score: r.score || 0,
|
|
432
|
+
is_subscribed: r.is_subscribed || false
|
|
433
|
+
}))
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Download resource — returns all files for the resource.
|
|
439
|
+
*
|
|
440
|
+
* GET /csp/api/resources/download/{id}
|
|
441
|
+
* Response: { data: { resource_id, name, type, version, hash, files: [{path, content}] } }
|
|
442
|
+
*
|
|
443
|
+
* files[].path is the relative path within the resource directory.
|
|
444
|
+
* Single-file resources (command, rule) have exactly one element.
|
|
445
|
+
* Multi-file resources (skill, mcp) have all their files included.
|
|
446
|
+
*/
|
|
447
|
+
async downloadResource(resourceId: string): Promise<{
|
|
448
|
+
resource_id: string;
|
|
449
|
+
name: string;
|
|
450
|
+
type: string;
|
|
451
|
+
version: string;
|
|
452
|
+
hash: string;
|
|
453
|
+
files: Array<{ path: string; content: string }>;
|
|
454
|
+
}> {
|
|
455
|
+
const response = await this.get<{
|
|
456
|
+
code: number;
|
|
457
|
+
result: string;
|
|
458
|
+
data: {
|
|
459
|
+
resource_id: string;
|
|
460
|
+
name: string;
|
|
461
|
+
type: string;
|
|
462
|
+
version: string;
|
|
463
|
+
hash: string;
|
|
464
|
+
files: Array<{ path: string; content: string }>;
|
|
465
|
+
};
|
|
466
|
+
}>(`/csp/api/resources/download/${resourceId}`);
|
|
467
|
+
return response.data;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get resource detail
|
|
472
|
+
*/
|
|
473
|
+
async getResourceDetail(resourceId: string): Promise<{
|
|
474
|
+
id: string;
|
|
475
|
+
name: string;
|
|
476
|
+
type: string;
|
|
477
|
+
team: string;
|
|
478
|
+
version: string;
|
|
479
|
+
description: string;
|
|
480
|
+
metadata: {
|
|
481
|
+
module: string;
|
|
482
|
+
tags: string[];
|
|
483
|
+
author: string;
|
|
484
|
+
created_at: string;
|
|
485
|
+
updated_at: string;
|
|
486
|
+
downloads: number;
|
|
487
|
+
file_size: number;
|
|
488
|
+
hash: string;
|
|
489
|
+
};
|
|
490
|
+
download_url: string;
|
|
491
|
+
}> {
|
|
492
|
+
return this.get(`/csp/api/resources/${resourceId}`);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Stage resource files for upload (Step 1 of two-step upload flow).
|
|
497
|
+
*
|
|
498
|
+
* POST /csp/api/resources/upload
|
|
499
|
+
* Body: { type, name, files: [{ path, content }] }
|
|
500
|
+
* Response: { upload_id, status, expires_at, preview_url }
|
|
501
|
+
*
|
|
502
|
+
* The server validates path traversal, total size (< 10 MB), and name conflicts.
|
|
503
|
+
* All file types are supported — mcp packages may include .py, .js, package.json, etc.
|
|
504
|
+
*/
|
|
505
|
+
async uploadResourceFiles(params: {
|
|
506
|
+
type: string;
|
|
507
|
+
name: string;
|
|
508
|
+
files: Array<{ path: string; content: string }>;
|
|
509
|
+
target_source?: string;
|
|
510
|
+
force?: boolean;
|
|
511
|
+
}): Promise<{
|
|
512
|
+
upload_id: string;
|
|
513
|
+
status: string;
|
|
514
|
+
expires_at: string;
|
|
515
|
+
preview_url?: string;
|
|
516
|
+
}> {
|
|
517
|
+
const resp = await this.post<{ code: number; result: string; data: { upload_id: string; status: string; expires_at: string; preview_url?: string } }>(
|
|
518
|
+
'/csp/api/resources/upload', params
|
|
519
|
+
);
|
|
520
|
+
return resp.data;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Finalize staged upload — triggers Git commit (Step 2 of two-step upload flow).
|
|
525
|
+
*
|
|
526
|
+
* POST /csp/api/resources/finalize
|
|
527
|
+
* Body: { upload_id, commit_message }
|
|
528
|
+
* Response: { resource_id, version, url, commit_hash, download_url }
|
|
529
|
+
*/
|
|
530
|
+
async finalizeResourceUpload(uploadId: string, commitMessage: string): Promise<{
|
|
531
|
+
resource_id: string;
|
|
532
|
+
version?: string;
|
|
533
|
+
url?: string;
|
|
534
|
+
commit_hash?: string;
|
|
535
|
+
download_url?: string;
|
|
536
|
+
}> {
|
|
537
|
+
const resp = await this.post<{ code: number; result: string; data: { resource_id: string; version?: string; url?: string; commit_hash?: string; download_url?: string } }>(
|
|
538
|
+
'/csp/api/resources/finalize', {
|
|
539
|
+
upload_id: uploadId,
|
|
540
|
+
commit_message: commitMessage,
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
return resp.data;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @deprecated Use uploadResourceFiles() + finalizeResourceUpload() instead.
|
|
548
|
+
*/
|
|
549
|
+
async uploadResource(params: {
|
|
550
|
+
name: string;
|
|
551
|
+
type: string;
|
|
552
|
+
team: string;
|
|
553
|
+
description?: string;
|
|
554
|
+
tags?: string[];
|
|
555
|
+
}): Promise<{
|
|
556
|
+
upload_id: string;
|
|
557
|
+
upload_url: string;
|
|
558
|
+
expires_at: string;
|
|
559
|
+
}> {
|
|
560
|
+
return this.post('/csp/api/resources/upload', params);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* @deprecated Use finalizeResourceUpload() instead.
|
|
565
|
+
*/
|
|
566
|
+
async finalizeUpload(uploadId: string, hash: string): Promise<{
|
|
567
|
+
resource_id: string;
|
|
568
|
+
status: string;
|
|
569
|
+
}> {
|
|
570
|
+
return this.post('/csp/api/resources/finalize', {
|
|
571
|
+
upload_id: uploadId,
|
|
572
|
+
hash,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Export singleton instance
|
|
578
|
+
export const apiClient = new APIClient();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication Module
|
|
3
|
+
* Exports all authentication and authorization utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Token validation via CSP API (primary method)
|
|
7
|
+
export * from './token-validator';
|
|
8
|
+
|
|
9
|
+
// Permissions and middleware
|
|
10
|
+
export * from './permissions';
|
|
11
|
+
export * from './middleware';
|