@kelpi/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/README.md +312 -0
- package/bin/kelpi-mcp +3 -0
- package/dist/__tests__/integration-api/fixtures.d.ts +382 -0
- package/dist/__tests__/integration-api/fixtures.d.ts.map +1 -0
- package/dist/__tests__/integration-api/fixtures.js +478 -0
- package/dist/__tests__/integration-api/fixtures.js.map +1 -0
- package/dist/__tests__/integration-api/index.d.ts +19 -0
- package/dist/__tests__/integration-api/index.d.ts.map +1 -0
- package/dist/__tests__/integration-api/index.js +33 -0
- package/dist/__tests__/integration-api/index.js.map +1 -0
- package/dist/__tests__/integration-api/setup.d.ts +176 -0
- package/dist/__tests__/integration-api/setup.d.ts.map +1 -0
- package/dist/__tests__/integration-api/setup.js +329 -0
- package/dist/__tests__/integration-api/setup.js.map +1 -0
- package/dist/__tests__/setup.d.ts +2 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +11 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/__tests__/unit/test-utils.d.ts +46 -0
- package/dist/__tests__/unit/test-utils.d.ts.map +1 -0
- package/dist/__tests__/unit/test-utils.js +50 -0
- package/dist/__tests__/unit/test-utils.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +17 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +169 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth-state.d.ts +54 -0
- package/dist/lib/auth-state.d.ts.map +1 -0
- package/dist/lib/auth-state.js +131 -0
- package/dist/lib/auth-state.js.map +1 -0
- package/dist/lib/config.d.ts +39 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +170 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/error-formatter.d.ts +40 -0
- package/dist/lib/error-formatter.d.ts.map +1 -0
- package/dist/lib/error-formatter.js +149 -0
- package/dist/lib/error-formatter.js.map +1 -0
- package/dist/lib/errors.d.ts +44 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +56 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/tool-helpers.d.ts +49 -0
- package/dist/lib/tool-helpers.d.ts.map +1 -0
- package/dist/lib/tool-helpers.js +101 -0
- package/dist/lib/tool-helpers.js.map +1 -0
- package/dist/lib/tool-registry.d.ts +111 -0
- package/dist/lib/tool-registry.d.ts.map +1 -0
- package/dist/lib/tool-registry.js +112 -0
- package/dist/lib/tool-registry.js.map +1 -0
- package/dist/lib/version.d.ts +13 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +13 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/prompts/flow-generator.d.ts +45 -0
- package/dist/prompts/flow-generator.d.ts.map +1 -0
- package/dist/prompts/flow-generator.js +177 -0
- package/dist/prompts/flow-generator.js.map +1 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +7 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/server.d.ts +66 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +140 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/auth/index.d.ts +18 -0
- package/dist/tools/auth/index.d.ts.map +1 -0
- package/dist/tools/auth/index.js +50 -0
- package/dist/tools/auth/index.js.map +1 -0
- package/dist/tools/auth/login.d.ts +37 -0
- package/dist/tools/auth/login.d.ts.map +1 -0
- package/dist/tools/auth/login.js +257 -0
- package/dist/tools/auth/login.js.map +1 -0
- package/dist/tools/auth/schemas.d.ts +69 -0
- package/dist/tools/auth/schemas.d.ts.map +1 -0
- package/dist/tools/auth/schemas.js +36 -0
- package/dist/tools/auth/schemas.js.map +1 -0
- package/dist/tools/auth/status.d.ts +11 -0
- package/dist/tools/auth/status.d.ts.map +1 -0
- package/dist/tools/auth/status.js +50 -0
- package/dist/tools/auth/status.js.map +1 -0
- package/dist/tools/contacts/create.d.ts +11 -0
- package/dist/tools/contacts/create.d.ts.map +1 -0
- package/dist/tools/contacts/create.js +47 -0
- package/dist/tools/contacts/create.js.map +1 -0
- package/dist/tools/contacts/index.d.ts +10 -0
- package/dist/tools/contacts/index.d.ts.map +1 -0
- package/dist/tools/contacts/index.js +40 -0
- package/dist/tools/contacts/index.js.map +1 -0
- package/dist/tools/contacts/schemas.d.ts +37 -0
- package/dist/tools/contacts/schemas.d.ts.map +1 -0
- package/dist/tools/contacts/schemas.js +15 -0
- package/dist/tools/contacts/schemas.js.map +1 -0
- package/dist/tools/events/index.d.ts +10 -0
- package/dist/tools/events/index.d.ts.map +1 -0
- package/dist/tools/events/index.js +42 -0
- package/dist/tools/events/index.js.map +1 -0
- package/dist/tools/events/schemas.d.ts +37 -0
- package/dist/tools/events/schemas.d.ts.map +1 -0
- package/dist/tools/events/schemas.js +17 -0
- package/dist/tools/events/schemas.js.map +1 -0
- package/dist/tools/events/track.d.ts +11 -0
- package/dist/tools/events/track.d.ts.map +1 -0
- package/dist/tools/events/track.js +41 -0
- package/dist/tools/events/track.js.map +1 -0
- package/dist/tools/flows/activate.d.ts +11 -0
- package/dist/tools/flows/activate.d.ts.map +1 -0
- package/dist/tools/flows/activate.js +46 -0
- package/dist/tools/flows/activate.js.map +1 -0
- package/dist/tools/flows/create.d.ts +11 -0
- package/dist/tools/flows/create.d.ts.map +1 -0
- package/dist/tools/flows/create.js +72 -0
- package/dist/tools/flows/create.js.map +1 -0
- package/dist/tools/flows/index.d.ts +24 -0
- package/dist/tools/flows/index.d.ts.map +1 -0
- package/dist/tools/flows/index.js +183 -0
- package/dist/tools/flows/index.js.map +1 -0
- package/dist/tools/flows/list.d.ts +11 -0
- package/dist/tools/flows/list.d.ts.map +1 -0
- package/dist/tools/flows/list.js +34 -0
- package/dist/tools/flows/list.js.map +1 -0
- package/dist/tools/flows/schemas.d.ts +621 -0
- package/dist/tools/flows/schemas.d.ts.map +1 -0
- package/dist/tools/flows/schemas.js +135 -0
- package/dist/tools/flows/schemas.js.map +1 -0
- package/dist/tools/flows/transform.d.ts +39 -0
- package/dist/tools/flows/transform.d.ts.map +1 -0
- package/dist/tools/flows/transform.js +139 -0
- package/dist/tools/flows/transform.js.map +1 -0
- package/dist/tools/index.d.ts +34 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +46 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/sdk/index.d.ts +18 -0
- package/dist/tools/sdk/index.d.ts.map +1 -0
- package/dist/tools/sdk/index.js +69 -0
- package/dist/tools/sdk/index.js.map +1 -0
- package/dist/tools/sdk/public-key.d.ts +11 -0
- package/dist/tools/sdk/public-key.d.ts.map +1 -0
- package/dist/tools/sdk/public-key.js +24 -0
- package/dist/tools/sdk/public-key.js.map +1 -0
- package/dist/tools/sdk/schemas.d.ts +48 -0
- package/dist/tools/sdk/schemas.d.ts.map +1 -0
- package/dist/tools/sdk/schemas.js +35 -0
- package/dist/tools/sdk/schemas.js.map +1 -0
- package/dist/tools/sdk/snippet.d.ts +11 -0
- package/dist/tools/sdk/snippet.d.ts.map +1 -0
- package/dist/tools/sdk/snippet.js +50 -0
- package/dist/tools/sdk/snippet.js.map +1 -0
- package/dist/tools/sdk/templates/index.d.ts +5 -0
- package/dist/tools/sdk/templates/index.d.ts.map +1 -0
- package/dist/tools/sdk/templates/index.js +5 -0
- package/dist/tools/sdk/templates/index.js.map +1 -0
- package/dist/tools/sdk/templates/nextjs.d.ts +5 -0
- package/dist/tools/sdk/templates/nextjs.d.ts.map +1 -0
- package/dist/tools/sdk/templates/nextjs.js +71 -0
- package/dist/tools/sdk/templates/nextjs.js.map +1 -0
- package/dist/tools/sdk/templates/node.d.ts +9 -0
- package/dist/tools/sdk/templates/node.d.ts.map +1 -0
- package/dist/tools/sdk/templates/node.js +170 -0
- package/dist/tools/sdk/templates/node.js.map +1 -0
- package/dist/tools/sdk/templates/react.d.ts +5 -0
- package/dist/tools/sdk/templates/react.d.ts.map +1 -0
- package/dist/tools/sdk/templates/react.js +54 -0
- package/dist/tools/sdk/templates/react.js.map +1 -0
- package/dist/tools/sdk/templates/vanilla.d.ts +5 -0
- package/dist/tools/sdk/templates/vanilla.d.ts.map +1 -0
- package/dist/tools/sdk/templates/vanilla.js +61 -0
- package/dist/tools/sdk/templates/vanilla.js.map +1 -0
- package/dist/tools/templates/create.d.ts +11 -0
- package/dist/tools/templates/create.d.ts.map +1 -0
- package/dist/tools/templates/create.js +39 -0
- package/dist/tools/templates/create.js.map +1 -0
- package/dist/tools/templates/index.d.ts +17 -0
- package/dist/tools/templates/index.d.ts.map +1 -0
- package/dist/tools/templates/index.js +68 -0
- package/dist/tools/templates/index.js.map +1 -0
- package/dist/tools/templates/list.d.ts +11 -0
- package/dist/tools/templates/list.d.ts.map +1 -0
- package/dist/tools/templates/list.js +31 -0
- package/dist/tools/templates/list.js.map +1 -0
- package/dist/tools/templates/schemas.d.ts +90 -0
- package/dist/tools/templates/schemas.d.ts.map +1 -0
- package/dist/tools/templates/schemas.js +37 -0
- package/dist/tools/templates/schemas.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +76 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { KelpiMcpServer } from './server.js';
|
|
3
|
+
/**
|
|
4
|
+
* Main entry point for the Kelpi MCP Server
|
|
5
|
+
*
|
|
6
|
+
* This starts the MCP server with stdio transport, making it available
|
|
7
|
+
* for use by AI assistants like Claude Desktop, Cursor, etc.
|
|
8
|
+
*/
|
|
9
|
+
async function main() {
|
|
10
|
+
const server = new KelpiMcpServer();
|
|
11
|
+
// Handle graceful shutdown
|
|
12
|
+
const shutdown = async () => {
|
|
13
|
+
await server.shutdown();
|
|
14
|
+
process.exit(0);
|
|
15
|
+
};
|
|
16
|
+
process.on('SIGINT', shutdown);
|
|
17
|
+
process.on('SIGTERM', shutdown);
|
|
18
|
+
try {
|
|
19
|
+
await server.start();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error('Failed to start Kelpi MCP server:', error);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
main().catch((error) => {
|
|
27
|
+
console.error('Unhandled error:', error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
// Re-export public API
|
|
31
|
+
export { KelpiMcpServer, createServer } from './server.js';
|
|
32
|
+
export { ToolRegistry, ToolRegistryError } from './lib/tool-registry.js';
|
|
33
|
+
export { ALL_TOOLS, TOOL_DEFINITIONS, TOOL_NAMES, } from './tools/index.js';
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;GAKG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;IAEpC,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,uBAAuB;AACvB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AASzE,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,UAAU,GAEX,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApiClientOptions, ApiResponse } from '../types.js';
|
|
2
|
+
export { ApiError, AuthError, TimeoutError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* API Client interface
|
|
5
|
+
*/
|
|
6
|
+
export interface ApiClient {
|
|
7
|
+
get<T = unknown>(path: string, params?: Record<string, string>): Promise<ApiResponse<T>>;
|
|
8
|
+
post<T = unknown>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
9
|
+
put<T = unknown>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
10
|
+
patch<T = unknown>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
11
|
+
delete<T = unknown>(path: string): Promise<ApiResponse<T>>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an API client with authentication and retry logic
|
|
15
|
+
*/
|
|
16
|
+
export declare function createApiClient(options: ApiClientOptions): ApiClient;
|
|
17
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AAGlF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA6BhE;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACzF,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5D;AA2DD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAgJpE"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Re-export error classes from errors.ts for convenience
|
|
2
|
+
export { ApiError, AuthError, TimeoutError } from './errors.js';
|
|
3
|
+
import { ApiError, AuthError, TimeoutError } from './errors.js';
|
|
4
|
+
import { MCP_VERSION } from './version.js';
|
|
5
|
+
/**
|
|
6
|
+
* Default API URL for Kelpi
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_API_URL = 'https://api.kelpi.ai';
|
|
9
|
+
/**
|
|
10
|
+
* Default timeout in milliseconds (30 seconds)
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
13
|
+
/**
|
|
14
|
+
* Default maximum retries for retryable errors
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
17
|
+
/**
|
|
18
|
+
* Default retry delay in milliseconds
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_RETRY_DELAY = 1000;
|
|
21
|
+
/**
|
|
22
|
+
* HTTP status codes that should trigger a retry
|
|
23
|
+
*/
|
|
24
|
+
const RETRYABLE_STATUS_CODES = [429, 503];
|
|
25
|
+
/**
|
|
26
|
+
* Sleep helper for retry delay
|
|
27
|
+
*/
|
|
28
|
+
function sleep(ms) {
|
|
29
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
30
|
+
}
|
|
31
|
+
async function parseErrorBody(response) {
|
|
32
|
+
try {
|
|
33
|
+
return (await response.json());
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { error: response.statusText };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format validation details from Zod's flatten() format into a readable message
|
|
41
|
+
*/
|
|
42
|
+
function formatValidationDetails(details) {
|
|
43
|
+
if (!details)
|
|
44
|
+
return '';
|
|
45
|
+
const messages = [];
|
|
46
|
+
// Add form-level errors
|
|
47
|
+
if (details.formErrors?.length) {
|
|
48
|
+
messages.push(...details.formErrors);
|
|
49
|
+
}
|
|
50
|
+
// Add field-level errors
|
|
51
|
+
if (details.fieldErrors) {
|
|
52
|
+
for (const [field, errors] of Object.entries(details.fieldErrors)) {
|
|
53
|
+
for (const error of errors) {
|
|
54
|
+
messages.push(`${field}: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return messages.join('; ');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create an API client with authentication and retry logic
|
|
62
|
+
*/
|
|
63
|
+
export function createApiClient(options) {
|
|
64
|
+
const { apiKey, apiUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT, maxRetries = DEFAULT_MAX_RETRIES, retryDelay = DEFAULT_RETRY_DELAY, } = options;
|
|
65
|
+
/**
|
|
66
|
+
* Build the full URL with query parameters
|
|
67
|
+
*/
|
|
68
|
+
function buildUrl(path, params) {
|
|
69
|
+
const url = new URL(path, apiUrl);
|
|
70
|
+
if (params) {
|
|
71
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
72
|
+
url.searchParams.set(key, value);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return url.toString();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get default headers for all requests
|
|
79
|
+
*/
|
|
80
|
+
function getHeaders() {
|
|
81
|
+
return {
|
|
82
|
+
Authorization: `Bearer ${apiKey}`,
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
'User-Agent': `kelpi-mcp/${MCP_VERSION}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Execute a request with timeout, error handling, and retry logic
|
|
89
|
+
*/
|
|
90
|
+
async function executeRequest(method, path, body, params, retriesRemaining = maxRetries) {
|
|
91
|
+
const url = buildUrl(path, params);
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
94
|
+
try {
|
|
95
|
+
const response = await fetch(url, {
|
|
96
|
+
method,
|
|
97
|
+
headers: getHeaders(),
|
|
98
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
});
|
|
101
|
+
clearTimeout(timeoutId);
|
|
102
|
+
// Handle successful responses
|
|
103
|
+
if (response.ok) {
|
|
104
|
+
// Handle 204 No Content
|
|
105
|
+
if (response.status === 204) {
|
|
106
|
+
return { data: null, status: response.status };
|
|
107
|
+
}
|
|
108
|
+
const data = (await response.json());
|
|
109
|
+
return { data, status: response.status };
|
|
110
|
+
}
|
|
111
|
+
// Handle error responses
|
|
112
|
+
const errorBody = await parseErrorBody(response);
|
|
113
|
+
// Build error message including validation details if present
|
|
114
|
+
let errorMessage = errorBody.error || errorBody.message || 'Request failed';
|
|
115
|
+
if (errorBody.details) {
|
|
116
|
+
const validationDetails = formatValidationDetails(errorBody.details);
|
|
117
|
+
if (validationDetails) {
|
|
118
|
+
errorMessage = `${errorMessage}: ${validationDetails}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Check if we should retry with exponential backoff
|
|
122
|
+
if (RETRYABLE_STATUS_CODES.includes(response.status) && retriesRemaining > 0) {
|
|
123
|
+
// Calculate exponential backoff with jitter
|
|
124
|
+
const attempt = maxRetries - retriesRemaining + 1;
|
|
125
|
+
const backoffDelay = retryDelay * Math.pow(2, attempt - 1);
|
|
126
|
+
const jitter = Math.random() * 1000;
|
|
127
|
+
await sleep(backoffDelay + jitter);
|
|
128
|
+
return executeRequest(method, path, body, params, retriesRemaining - 1);
|
|
129
|
+
}
|
|
130
|
+
// Handle 401 Unauthorized
|
|
131
|
+
if (response.status === 401) {
|
|
132
|
+
throw new AuthError(errorMessage);
|
|
133
|
+
}
|
|
134
|
+
// Throw ApiError for all other error responses
|
|
135
|
+
throw new ApiError(errorMessage, response.status, errorBody.errors, errorBody.details);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
clearTimeout(timeoutId);
|
|
139
|
+
// Re-throw our custom errors
|
|
140
|
+
if (error instanceof ApiError || error instanceof AuthError || error instanceof TimeoutError) {
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
// Handle abort (timeout)
|
|
144
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
145
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
|
|
146
|
+
}
|
|
147
|
+
// Handle other fetch errors
|
|
148
|
+
throw new ApiError(error instanceof Error ? error.message : 'Unknown error', 0);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
async get(path, params) {
|
|
153
|
+
return executeRequest('GET', path, undefined, params);
|
|
154
|
+
},
|
|
155
|
+
async post(path, body) {
|
|
156
|
+
return executeRequest('POST', path, body);
|
|
157
|
+
},
|
|
158
|
+
async put(path, body) {
|
|
159
|
+
return executeRequest('PUT', path, body);
|
|
160
|
+
},
|
|
161
|
+
async patch(path, body) {
|
|
162
|
+
return executeRequest('PATCH', path, body);
|
|
163
|
+
},
|
|
164
|
+
async delete(path) {
|
|
165
|
+
return executeRequest('DELETE', path);
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { KelpiConfig, AuthState as AuthStateType } from '../types.js';
|
|
2
|
+
export type AuthState = AuthStateType;
|
|
3
|
+
/**
|
|
4
|
+
* Manages authentication state for the MCP server.
|
|
5
|
+
* Supports caching and refresh of authentication state.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AuthStateManager {
|
|
8
|
+
private cachedState;
|
|
9
|
+
private config;
|
|
10
|
+
/**
|
|
11
|
+
* Create a new AuthStateManager.
|
|
12
|
+
* @param config - Optional config to use instead of loading from file
|
|
13
|
+
*/
|
|
14
|
+
constructor(config?: KelpiConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Get the current authentication state.
|
|
17
|
+
* Returns cached state if available, or fetches from API.
|
|
18
|
+
* @param fetchIfNeeded - If true (default), fetch from API if not cached
|
|
19
|
+
*/
|
|
20
|
+
getState(fetchIfNeeded?: boolean): Promise<AuthState>;
|
|
21
|
+
/**
|
|
22
|
+
* Refresh the authentication state by clearing cache and re-fetching.
|
|
23
|
+
*/
|
|
24
|
+
refresh(): Promise<AuthState>;
|
|
25
|
+
/**
|
|
26
|
+
* Clear the cached authentication state.
|
|
27
|
+
*/
|
|
28
|
+
clearState(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get the key type from the API key prefix.
|
|
31
|
+
*/
|
|
32
|
+
private getKeyType;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch workspace info from the API.
|
|
35
|
+
*/
|
|
36
|
+
private fetchWorkspaceInfo;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the current authentication state.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAuthState(): Promise<AuthState>;
|
|
42
|
+
/**
|
|
43
|
+
* Check if currently authenticated.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isAuthenticated(): Promise<boolean>;
|
|
46
|
+
/**
|
|
47
|
+
* Refresh and return the authentication state.
|
|
48
|
+
*/
|
|
49
|
+
export declare function refreshAuthState(): Promise<AuthState>;
|
|
50
|
+
/**
|
|
51
|
+
* Clear the cached authentication state.
|
|
52
|
+
*/
|
|
53
|
+
export declare function clearAuthState(): void;
|
|
54
|
+
//# sourceMappingURL=auth-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-state.d.ts","sourceRoot":"","sources":["../../src/lib/auth-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,aAAa,CAAC;AAK3E,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC;AAYtC;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAAqB;IAEnC;;;OAGG;gBACS,MAAM,CAAC,EAAE,WAAW;IAIhC;;;;OAIG;IACG,QAAQ,CAAC,aAAa,UAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IA+CxD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAKnC;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,OAAO,CAAC,UAAU;IASlB;;OAEG;YACW,kBAAkB;CAIjC;AAYD;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC,CAEvD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,SAAS,CAAC,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAMrC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { loadConfig } from './config.js';
|
|
2
|
+
import { createApiClient } from './api-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages authentication state for the MCP server.
|
|
5
|
+
* Supports caching and refresh of authentication state.
|
|
6
|
+
*/
|
|
7
|
+
export class AuthStateManager {
|
|
8
|
+
cachedState = null;
|
|
9
|
+
config;
|
|
10
|
+
/**
|
|
11
|
+
* Create a new AuthStateManager.
|
|
12
|
+
* @param config - Optional config to use instead of loading from file
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config || null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get the current authentication state.
|
|
19
|
+
* Returns cached state if available, or fetches from API.
|
|
20
|
+
* @param fetchIfNeeded - If true (default), fetch from API if not cached
|
|
21
|
+
*/
|
|
22
|
+
async getState(fetchIfNeeded = true) {
|
|
23
|
+
// Return cached state if available
|
|
24
|
+
if (this.cachedState !== null) {
|
|
25
|
+
return this.cachedState;
|
|
26
|
+
}
|
|
27
|
+
// If not fetching, return unauthenticated state
|
|
28
|
+
if (!fetchIfNeeded) {
|
|
29
|
+
return { authenticated: false };
|
|
30
|
+
}
|
|
31
|
+
// Load config if not provided
|
|
32
|
+
const config = this.config || await loadConfig();
|
|
33
|
+
// If no API key, return unauthenticated state
|
|
34
|
+
if (!config.api_key) {
|
|
35
|
+
this.cachedState = { authenticated: false };
|
|
36
|
+
return this.cachedState;
|
|
37
|
+
}
|
|
38
|
+
// Determine key type from prefix
|
|
39
|
+
const keyType = this.getKeyType(config.api_key);
|
|
40
|
+
// Create API client and fetch workspace info
|
|
41
|
+
try {
|
|
42
|
+
const client = createApiClient({
|
|
43
|
+
apiKey: config.api_key,
|
|
44
|
+
apiUrl: config.api_url,
|
|
45
|
+
});
|
|
46
|
+
const workspaceInfo = await this.fetchWorkspaceInfo(client);
|
|
47
|
+
this.cachedState = {
|
|
48
|
+
authenticated: true,
|
|
49
|
+
workspace_id: workspaceInfo.workspace.id,
|
|
50
|
+
workspace_name: workspaceInfo.workspace.name,
|
|
51
|
+
key_type: keyType,
|
|
52
|
+
};
|
|
53
|
+
return this.cachedState;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// If API call fails, mark as unauthenticated
|
|
57
|
+
this.cachedState = { authenticated: false };
|
|
58
|
+
return this.cachedState;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Refresh the authentication state by clearing cache and re-fetching.
|
|
63
|
+
*/
|
|
64
|
+
async refresh() {
|
|
65
|
+
this.cachedState = null;
|
|
66
|
+
return this.getState();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Clear the cached authentication state.
|
|
70
|
+
*/
|
|
71
|
+
clearState() {
|
|
72
|
+
this.cachedState = null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the key type from the API key prefix.
|
|
76
|
+
*/
|
|
77
|
+
getKeyType(apiKey) {
|
|
78
|
+
if (apiKey.startsWith('klp_sk_')) {
|
|
79
|
+
return 'secret';
|
|
80
|
+
}
|
|
81
|
+
else if (apiKey.startsWith('klp_pk_')) {
|
|
82
|
+
return 'public';
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fetch workspace info from the API.
|
|
88
|
+
*/
|
|
89
|
+
async fetchWorkspaceInfo(client) {
|
|
90
|
+
const response = await client.get('/api/v1/auth/me');
|
|
91
|
+
return response.data;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Singleton instance for module-level functions
|
|
95
|
+
let defaultManager = null;
|
|
96
|
+
function getManager() {
|
|
97
|
+
if (!defaultManager) {
|
|
98
|
+
defaultManager = new AuthStateManager();
|
|
99
|
+
}
|
|
100
|
+
return defaultManager;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the current authentication state.
|
|
104
|
+
*/
|
|
105
|
+
export async function getAuthState() {
|
|
106
|
+
return getManager().getState();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if currently authenticated.
|
|
110
|
+
*/
|
|
111
|
+
export async function isAuthenticated() {
|
|
112
|
+
const state = await getAuthState();
|
|
113
|
+
return state.authenticated;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Refresh and return the authentication state.
|
|
117
|
+
*/
|
|
118
|
+
export async function refreshAuthState() {
|
|
119
|
+
return getManager().refresh();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear the cached authentication state.
|
|
123
|
+
*/
|
|
124
|
+
export function clearAuthState() {
|
|
125
|
+
if (defaultManager) {
|
|
126
|
+
defaultManager.clearState();
|
|
127
|
+
}
|
|
128
|
+
// Also reset the manager so next call creates fresh instance
|
|
129
|
+
defaultManager = null;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=auth-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-state.js","sourceRoot":"","sources":["../../src/lib/auth-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { KelpiConfig, ConfigValidationResult, SaveConfigOptions } from '../types.js';
|
|
2
|
+
export { ConfigError } from './errors.js';
|
|
3
|
+
export type { KelpiConfig } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the path to the config file.
|
|
6
|
+
* Uses KELPI_CONFIG_PATH env var if set, otherwise ~/.kelpi/config.json
|
|
7
|
+
*/
|
|
8
|
+
export declare function getConfigPath(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Loads configuration from file and merges with environment variables.
|
|
11
|
+
* Environment variables take precedence over file values.
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadConfig(): Promise<KelpiConfig>;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the API key from environment variable or config file.
|
|
16
|
+
* Environment variable takes precedence.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getApiKey(): Promise<string | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the API URL from environment variable, config file, or default.
|
|
21
|
+
* Priority: env var > config file > default
|
|
22
|
+
*/
|
|
23
|
+
export declare function getApiUrl(): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Saves configuration to file.
|
|
26
|
+
* Creates the config directory if it doesn't exist.
|
|
27
|
+
*
|
|
28
|
+
* @param config - Configuration to save
|
|
29
|
+
* @param options - Save options
|
|
30
|
+
* @param options.merge - If true, merges with existing config.
|
|
31
|
+
* Warning: Not atomic. Concurrent saves may cause data loss.
|
|
32
|
+
*/
|
|
33
|
+
export declare function saveConfig(config: KelpiConfig, options?: SaveConfigOptions): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Validates the configuration object.
|
|
36
|
+
* Checks API key format and URL validity.
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateConfig(config: KelpiConfig): ConfigValidationResult;
|
|
39
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG1F,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA2B/C;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAMtC;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CA8BvD;AAED;;;GAGG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7D;AAED;;;GAGG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAOjD;AAuBD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,sBAAsB,CA6B1E"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import fsPromises from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
// Re-export ConfigError from errors.ts for convenience
|
|
5
|
+
export { ConfigError } from './errors.js';
|
|
6
|
+
import { ConfigError } from './errors.js';
|
|
7
|
+
/**
|
|
8
|
+
* Default API URL for Kelpi
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_API_URL = 'https://api.kelpi.ai';
|
|
11
|
+
/**
|
|
12
|
+
* Default config directory name
|
|
13
|
+
*/
|
|
14
|
+
const CONFIG_DIR = '.kelpi';
|
|
15
|
+
/**
|
|
16
|
+
* Config file name
|
|
17
|
+
*/
|
|
18
|
+
const CONFIG_FILE = 'config.json';
|
|
19
|
+
/**
|
|
20
|
+
* Expands ~ to the user's home directory
|
|
21
|
+
*/
|
|
22
|
+
function expandTilde(filepath) {
|
|
23
|
+
if (filepath.startsWith('~/')) {
|
|
24
|
+
return path.join(homedir(), filepath.slice(2));
|
|
25
|
+
}
|
|
26
|
+
return filepath;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the path to the config file.
|
|
30
|
+
* Uses KELPI_CONFIG_PATH env var if set, otherwise ~/.kelpi/config.json
|
|
31
|
+
*/
|
|
32
|
+
export function getConfigPath() {
|
|
33
|
+
const envPath = process.env.KELPI_CONFIG_PATH;
|
|
34
|
+
if (envPath) {
|
|
35
|
+
return expandTilde(envPath);
|
|
36
|
+
}
|
|
37
|
+
return path.join(homedir(), CONFIG_DIR, CONFIG_FILE);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads configuration from file and merges with environment variables.
|
|
41
|
+
* Environment variables take precedence over file values.
|
|
42
|
+
*/
|
|
43
|
+
export async function loadConfig() {
|
|
44
|
+
const configPath = getConfigPath();
|
|
45
|
+
let fileConfig = {};
|
|
46
|
+
try {
|
|
47
|
+
const content = await fsPromises.readFile(configPath, 'utf8');
|
|
48
|
+
fileConfig = JSON.parse(content);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error.code === 'ENOENT') {
|
|
52
|
+
// Config file doesn't exist, that's OK
|
|
53
|
+
fileConfig = {};
|
|
54
|
+
}
|
|
55
|
+
else if (error instanceof SyntaxError) {
|
|
56
|
+
throw new ConfigError('Invalid config file: malformed JSON');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Merge with environment variables (env vars take precedence)
|
|
63
|
+
const config = { ...fileConfig };
|
|
64
|
+
if (process.env.KELPI_API_KEY) {
|
|
65
|
+
config.api_key = process.env.KELPI_API_KEY;
|
|
66
|
+
}
|
|
67
|
+
if (process.env.KELPI_API_URL) {
|
|
68
|
+
config.api_url = process.env.KELPI_API_URL;
|
|
69
|
+
}
|
|
70
|
+
return config;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns the API key from environment variable or config file.
|
|
74
|
+
* Environment variable takes precedence.
|
|
75
|
+
*/
|
|
76
|
+
export async function getApiKey() {
|
|
77
|
+
if (process.env.KELPI_API_KEY) {
|
|
78
|
+
return process.env.KELPI_API_KEY;
|
|
79
|
+
}
|
|
80
|
+
const config = await loadConfig();
|
|
81
|
+
return config.api_key;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns the API URL from environment variable, config file, or default.
|
|
85
|
+
* Priority: env var > config file > default
|
|
86
|
+
*/
|
|
87
|
+
export async function getApiUrl() {
|
|
88
|
+
if (process.env.KELPI_API_URL) {
|
|
89
|
+
return process.env.KELPI_API_URL;
|
|
90
|
+
}
|
|
91
|
+
const config = await loadConfig();
|
|
92
|
+
return config.api_url || DEFAULT_API_URL;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns the directory containing the config file
|
|
96
|
+
*/
|
|
97
|
+
function getConfigDir() {
|
|
98
|
+
return path.dirname(getConfigPath());
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Loads config from file only (without env var merge)
|
|
102
|
+
*/
|
|
103
|
+
async function loadConfigFromFile() {
|
|
104
|
+
const configPath = getConfigPath();
|
|
105
|
+
try {
|
|
106
|
+
const content = await fsPromises.readFile(configPath, 'utf8');
|
|
107
|
+
return JSON.parse(content);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Saves configuration to file.
|
|
115
|
+
* Creates the config directory if it doesn't exist.
|
|
116
|
+
*
|
|
117
|
+
* @param config - Configuration to save
|
|
118
|
+
* @param options - Save options
|
|
119
|
+
* @param options.merge - If true, merges with existing config.
|
|
120
|
+
* Warning: Not atomic. Concurrent saves may cause data loss.
|
|
121
|
+
*/
|
|
122
|
+
export async function saveConfig(config, options = {}) {
|
|
123
|
+
const configPath = getConfigPath();
|
|
124
|
+
const configDir = getConfigDir();
|
|
125
|
+
// Ensure directory exists
|
|
126
|
+
await fsPromises.mkdir(configDir, { recursive: true, mode: 0o700 });
|
|
127
|
+
let finalConfig = config;
|
|
128
|
+
if (options.merge) {
|
|
129
|
+
const existingFileConfig = await loadConfigFromFile();
|
|
130
|
+
finalConfig = { ...existingFileConfig, ...config };
|
|
131
|
+
}
|
|
132
|
+
// Write with restricted permissions (readable/writable only by owner)
|
|
133
|
+
await fsPromises.writeFile(configPath, JSON.stringify(finalConfig, null, 2) + '\n', {
|
|
134
|
+
mode: 0o600,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Validates the configuration object.
|
|
139
|
+
* Checks API key format and URL validity.
|
|
140
|
+
*/
|
|
141
|
+
export function validateConfig(config) {
|
|
142
|
+
const errors = [];
|
|
143
|
+
// Validate API key if present
|
|
144
|
+
if (config.api_key !== undefined) {
|
|
145
|
+
if (!config.api_key.startsWith('klp_sk_') && !config.api_key.startsWith('klp_pk_')) {
|
|
146
|
+
errors.push('API key must start with klp_sk_ or klp_pk_');
|
|
147
|
+
}
|
|
148
|
+
else if (config.api_key.length <= 7) {
|
|
149
|
+
// klp_sk_ or klp_pk_ is 7 characters, key should be longer
|
|
150
|
+
errors.push('API key is too short');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Validate API URL if present
|
|
154
|
+
if (config.api_url !== undefined) {
|
|
155
|
+
try {
|
|
156
|
+
const url = new URL(config.api_url);
|
|
157
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
158
|
+
errors.push('API URL must be a valid HTTP(S) URL');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
errors.push('API URL must be a valid HTTP(S) URL');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
valid: errors.length === 0,
|
|
167
|
+
errors,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|