@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.
Files changed (191) hide show
  1. package/dist/api/cached-client.d.ts +48 -0
  2. package/dist/api/cached-client.d.ts.map +1 -0
  3. package/dist/api/cached-client.js +126 -0
  4. package/dist/api/cached-client.js.map +1 -0
  5. package/dist/api/client.d.ts +213 -0
  6. package/dist/api/client.d.ts.map +1 -0
  7. package/dist/api/client.js +326 -0
  8. package/dist/api/client.js.map +1 -0
  9. package/dist/auth/index.d.ts +8 -0
  10. package/dist/auth/index.d.ts.map +1 -0
  11. package/dist/auth/index.js +26 -0
  12. package/dist/auth/index.js.map +1 -0
  13. package/dist/auth/middleware.d.ts +36 -0
  14. package/dist/auth/middleware.d.ts.map +1 -0
  15. package/dist/auth/middleware.js +194 -0
  16. package/dist/auth/middleware.js.map +1 -0
  17. package/dist/auth/permissions.d.ts +60 -0
  18. package/dist/auth/permissions.d.ts.map +1 -0
  19. package/dist/auth/permissions.js +256 -0
  20. package/dist/auth/permissions.js.map +1 -0
  21. package/dist/auth/token-validator.d.ts +52 -0
  22. package/dist/auth/token-validator.d.ts.map +1 -0
  23. package/dist/auth/token-validator.js +217 -0
  24. package/dist/auth/token-validator.js.map +1 -0
  25. package/dist/cache/cache-manager.d.ts +49 -0
  26. package/dist/cache/cache-manager.d.ts.map +1 -0
  27. package/dist/cache/cache-manager.js +191 -0
  28. package/dist/cache/cache-manager.js.map +1 -0
  29. package/dist/cache/index.d.ts +6 -0
  30. package/dist/cache/index.d.ts.map +1 -0
  31. package/dist/cache/index.js +12 -0
  32. package/dist/cache/index.js.map +1 -0
  33. package/dist/cache/redis-client.d.ts +45 -0
  34. package/dist/cache/redis-client.d.ts.map +1 -0
  35. package/dist/cache/redis-client.js +210 -0
  36. package/dist/cache/redis-client.js.map +1 -0
  37. package/dist/config/constants.d.ts +28 -0
  38. package/dist/config/constants.d.ts.map +1 -0
  39. package/dist/config/constants.js +31 -0
  40. package/dist/config/constants.js.map +1 -0
  41. package/dist/config/index.d.ts +54 -0
  42. package/dist/config/index.d.ts.map +1 -0
  43. package/dist/config/index.js +168 -0
  44. package/dist/config/index.js.map +1 -0
  45. package/dist/filesystem/manager.d.ts +45 -0
  46. package/dist/filesystem/manager.d.ts.map +1 -0
  47. package/dist/filesystem/manager.js +246 -0
  48. package/dist/filesystem/manager.js.map +1 -0
  49. package/dist/git/multi-source-manager.d.ts +62 -0
  50. package/dist/git/multi-source-manager.d.ts.map +1 -0
  51. package/dist/git/multi-source-manager.js +293 -0
  52. package/dist/git/multi-source-manager.js.map +1 -0
  53. package/dist/git/operations.d.ts +27 -0
  54. package/dist/git/operations.d.ts.map +1 -0
  55. package/dist/git/operations.js +83 -0
  56. package/dist/git/operations.js.map +1 -0
  57. package/dist/index.d.ts +6 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +109 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/monitoring/health.d.ts +35 -0
  62. package/dist/monitoring/health.d.ts.map +1 -0
  63. package/dist/monitoring/health.js +105 -0
  64. package/dist/monitoring/health.js.map +1 -0
  65. package/dist/resources/index.d.ts +6 -0
  66. package/dist/resources/index.d.ts.map +1 -0
  67. package/dist/resources/index.js +10 -0
  68. package/dist/resources/index.js.map +1 -0
  69. package/dist/resources/loader.d.ts +87 -0
  70. package/dist/resources/loader.d.ts.map +1 -0
  71. package/dist/resources/loader.js +452 -0
  72. package/dist/resources/loader.js.map +1 -0
  73. package/dist/server/http.d.ts +57 -0
  74. package/dist/server/http.d.ts.map +1 -0
  75. package/dist/server/http.js +336 -0
  76. package/dist/server/http.js.map +1 -0
  77. package/dist/server.d.ts +13 -0
  78. package/dist/server.d.ts.map +1 -0
  79. package/dist/server.js +157 -0
  80. package/dist/server.js.map +1 -0
  81. package/dist/session/manager.d.ts +91 -0
  82. package/dist/session/manager.d.ts.map +1 -0
  83. package/dist/session/manager.js +251 -0
  84. package/dist/session/manager.js.map +1 -0
  85. package/dist/tools/index.d.ts +11 -0
  86. package/dist/tools/index.d.ts.map +1 -0
  87. package/dist/tools/index.js +27 -0
  88. package/dist/tools/index.js.map +1 -0
  89. package/dist/tools/manage-subscription.d.ts +43 -0
  90. package/dist/tools/manage-subscription.d.ts.map +1 -0
  91. package/dist/tools/manage-subscription.js +268 -0
  92. package/dist/tools/manage-subscription.js.map +1 -0
  93. package/dist/tools/registry.d.ts +40 -0
  94. package/dist/tools/registry.d.ts.map +1 -0
  95. package/dist/tools/registry.js +85 -0
  96. package/dist/tools/registry.js.map +1 -0
  97. package/dist/tools/search-resources.d.ts +31 -0
  98. package/dist/tools/search-resources.d.ts.map +1 -0
  99. package/dist/tools/search-resources.js +154 -0
  100. package/dist/tools/search-resources.js.map +1 -0
  101. package/dist/tools/sync-resources.d.ts +41 -0
  102. package/dist/tools/sync-resources.d.ts.map +1 -0
  103. package/dist/tools/sync-resources.js +606 -0
  104. package/dist/tools/sync-resources.js.map +1 -0
  105. package/dist/tools/uninstall-resource.d.ts +30 -0
  106. package/dist/tools/uninstall-resource.d.ts.map +1 -0
  107. package/dist/tools/uninstall-resource.js +259 -0
  108. package/dist/tools/uninstall-resource.js.map +1 -0
  109. package/dist/tools/upload-resource.d.ts +77 -0
  110. package/dist/tools/upload-resource.d.ts.map +1 -0
  111. package/dist/tools/upload-resource.js +252 -0
  112. package/dist/tools/upload-resource.js.map +1 -0
  113. package/dist/transport/sse.d.ts +29 -0
  114. package/dist/transport/sse.d.ts.map +1 -0
  115. package/dist/transport/sse.js +271 -0
  116. package/dist/transport/sse.js.map +1 -0
  117. package/dist/types/errors.d.ts +60 -0
  118. package/dist/types/errors.d.ts.map +1 -0
  119. package/dist/types/errors.js +112 -0
  120. package/dist/types/errors.js.map +1 -0
  121. package/dist/types/index.d.ts +7 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +23 -0
  124. package/dist/types/index.js.map +1 -0
  125. package/dist/types/mcp.d.ts +50 -0
  126. package/dist/types/mcp.d.ts.map +1 -0
  127. package/dist/types/mcp.js +6 -0
  128. package/dist/types/mcp.js.map +1 -0
  129. package/dist/types/resources.d.ts +109 -0
  130. package/dist/types/resources.d.ts.map +1 -0
  131. package/dist/types/resources.js +7 -0
  132. package/dist/types/resources.js.map +1 -0
  133. package/dist/types/tools.d.ts +147 -0
  134. package/dist/types/tools.d.ts.map +1 -0
  135. package/dist/types/tools.js +6 -0
  136. package/dist/types/tools.js.map +1 -0
  137. package/dist/utils/cursor-paths.d.ts +49 -0
  138. package/dist/utils/cursor-paths.d.ts.map +1 -0
  139. package/dist/utils/cursor-paths.js +116 -0
  140. package/dist/utils/cursor-paths.js.map +1 -0
  141. package/dist/utils/log-cleaner.d.ts +18 -0
  142. package/dist/utils/log-cleaner.d.ts.map +1 -0
  143. package/dist/utils/log-cleaner.js +112 -0
  144. package/dist/utils/log-cleaner.js.map +1 -0
  145. package/dist/utils/logger.d.ts +59 -0
  146. package/dist/utils/logger.d.ts.map +1 -0
  147. package/dist/utils/logger.js +292 -0
  148. package/dist/utils/logger.js.map +1 -0
  149. package/dist/utils/validation.d.ts +58 -0
  150. package/dist/utils/validation.d.ts.map +1 -0
  151. package/dist/utils/validation.js +214 -0
  152. package/dist/utils/validation.js.map +1 -0
  153. package/package.json +58 -0
  154. package/src/api/cached-client.ts +144 -0
  155. package/src/api/client.ts +578 -0
  156. package/src/auth/index.ts +11 -0
  157. package/src/auth/middleware.ts +244 -0
  158. package/src/auth/permissions.ts +317 -0
  159. package/src/auth/token-validator.ts +294 -0
  160. package/src/cache/cache-manager.ts +243 -0
  161. package/src/cache/index.ts +6 -0
  162. package/src/cache/redis-client.ts +249 -0
  163. package/src/config/constants.ts +33 -0
  164. package/src/config/index.ts +228 -0
  165. package/src/filesystem/manager.ts +235 -0
  166. package/src/git/multi-source-manager.ts +333 -0
  167. package/src/git/operations.ts +93 -0
  168. package/src/index.ts +139 -0
  169. package/src/monitoring/health.ts +132 -0
  170. package/src/resources/index.ts +13 -0
  171. package/src/resources/loader.ts +530 -0
  172. package/src/server/http.ts +427 -0
  173. package/src/server.ts +191 -0
  174. package/src/session/manager.ts +296 -0
  175. package/src/tools/index.ts +11 -0
  176. package/src/tools/manage-subscription.ts +332 -0
  177. package/src/tools/registry.ts +97 -0
  178. package/src/tools/search-resources.ts +177 -0
  179. package/src/tools/sync-resources.ts +662 -0
  180. package/src/tools/uninstall-resource.ts +248 -0
  181. package/src/tools/upload-resource.ts +258 -0
  182. package/src/transport/sse.ts +308 -0
  183. package/src/types/errors.ts +146 -0
  184. package/src/types/index.ts +7 -0
  185. package/src/types/mcp.ts +61 -0
  186. package/src/types/resources.ts +141 -0
  187. package/src/types/tools.ts +175 -0
  188. package/src/utils/cursor-paths.ts +83 -0
  189. package/src/utils/log-cleaner.ts +92 -0
  190. package/src/utils/logger.ts +333 -0
  191. 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';