@barndoor-ai/sdk 0.2.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/.eslintignore +8 -0
- package/.eslintrc.cjs +102 -0
- package/.github/CODEOWNERS +4 -0
- package/.github/workflows/ci.yml +57 -0
- package/.prettierignore +6 -0
- package/.prettierrc +13 -0
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/RELEASE.md +203 -0
- package/examples/README.md +92 -0
- package/examples/basic-mcp-client.js +134 -0
- package/examples/openai-integration.js +137 -0
- package/jest.config.js +16 -0
- package/openapi.yaml +681 -0
- package/package.json +87 -0
- package/rollup.config.js +63 -0
- package/scripts/dump-core-files.js +161 -0
- package/scripts/dump-typescript-only.js +150 -0
- package/src/auth/index.ts +26 -0
- package/src/auth/pkce.ts +346 -0
- package/src/auth/store.ts +809 -0
- package/src/client.ts +512 -0
- package/src/config.ts +402 -0
- package/src/exceptions/index.ts +205 -0
- package/src/http/client.ts +272 -0
- package/src/index.ts +92 -0
- package/src/logging.ts +111 -0
- package/src/models/index.ts +156 -0
- package/src/quickstart.ts +358 -0
- package/src/version.ts +41 -0
- package/test/client.test.js +381 -0
- package/test/config.test.js +202 -0
- package/test/exceptions.test.js +142 -0
- package/test/integration.test.js +147 -0
- package/test/models.test.js +177 -0
- package/test/token-management.test.js +81 -0
- package/test/token-validation.test.js +104 -0
- package/tsconfig.json +61 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client with retry logic and error handling.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a robust HTTP client that mirrors the Python SDK's
|
|
5
|
+
* HTTP client functionality, including automatic retries, timeout handling,
|
|
6
|
+
* and proper error conversion.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { HTTPError, ConnectionError, TimeoutError } from '../exceptions';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* HTTP request options interface.
|
|
13
|
+
*/
|
|
14
|
+
export interface HTTPRequestOptions {
|
|
15
|
+
/** Request headers */
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
/** JSON body to send */
|
|
18
|
+
json?: unknown;
|
|
19
|
+
/** Query parameters */
|
|
20
|
+
params?: Record<string, string | number | boolean>;
|
|
21
|
+
/** Additional fetch options */
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Timeout configuration for HTTP requests.
|
|
27
|
+
*/
|
|
28
|
+
export class TimeoutConfig {
|
|
29
|
+
/** Read timeout in milliseconds */
|
|
30
|
+
public readonly read: number;
|
|
31
|
+
/** Connect timeout in milliseconds */
|
|
32
|
+
public readonly connect: number;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a new TimeoutConfig.
|
|
36
|
+
* @param read - Read timeout in seconds
|
|
37
|
+
* @param connect - Connect timeout in seconds
|
|
38
|
+
*/
|
|
39
|
+
constructor(read = 30, connect = 10) {
|
|
40
|
+
this.read = read * 1000; // Convert to milliseconds
|
|
41
|
+
this.connect = connect * 1000; // Convert to milliseconds
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* HTTP client with automatic retries and error handling.
|
|
47
|
+
*
|
|
48
|
+
* Provides a consistent interface for making HTTP requests with proper
|
|
49
|
+
* error handling, timeout management, and retry logic.
|
|
50
|
+
*/
|
|
51
|
+
export class HTTPClient {
|
|
52
|
+
/** Timeout configuration */
|
|
53
|
+
private readonly timeoutConfig: TimeoutConfig;
|
|
54
|
+
/** Maximum number of retries */
|
|
55
|
+
private readonly maxRetries: number;
|
|
56
|
+
/** Whether the client has been closed */
|
|
57
|
+
public closed: boolean;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a new HTTPClient.
|
|
61
|
+
* @param timeoutConfig - Timeout configuration
|
|
62
|
+
* @param maxRetries - Maximum number of retries
|
|
63
|
+
*/
|
|
64
|
+
constructor(timeoutConfig = new TimeoutConfig(), maxRetries = 3) {
|
|
65
|
+
this.timeoutConfig = timeoutConfig;
|
|
66
|
+
this.maxRetries = maxRetries;
|
|
67
|
+
this.closed = false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Make an HTTP request with retry logic.
|
|
72
|
+
* @param method - HTTP method
|
|
73
|
+
* @param url - Request URL
|
|
74
|
+
* @param options - Request options
|
|
75
|
+
* @returns Response data
|
|
76
|
+
*/
|
|
77
|
+
public async request(
|
|
78
|
+
method: string,
|
|
79
|
+
url: string,
|
|
80
|
+
options: HTTPRequestOptions = {}
|
|
81
|
+
): Promise<unknown> {
|
|
82
|
+
if (this.closed) {
|
|
83
|
+
throw new Error('HTTP client has been closed');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const { headers = {}, json, params, ...fetchOptions } = options;
|
|
87
|
+
|
|
88
|
+
// Build URL with query parameters
|
|
89
|
+
const requestUrl = this._buildUrl(url, params);
|
|
90
|
+
|
|
91
|
+
// Prepare request options
|
|
92
|
+
const requestOptions: RequestInit = {
|
|
93
|
+
method: method.toUpperCase(),
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
'User-Agent': 'barndoor-js-sdk/0.1.0',
|
|
97
|
+
...headers,
|
|
98
|
+
},
|
|
99
|
+
...fetchOptions,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Add request body if provided
|
|
103
|
+
if (json) {
|
|
104
|
+
requestOptions.body = JSON.stringify(json);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let lastError: Error | undefined;
|
|
108
|
+
|
|
109
|
+
// Retry loop
|
|
110
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
111
|
+
// Create fresh AbortController and timeout for each attempt
|
|
112
|
+
const controller = new AbortController();
|
|
113
|
+
|
|
114
|
+
// Set up overall request timeout (covers both connection and read)
|
|
115
|
+
const totalTimeout = this.timeoutConfig.connect + this.timeoutConfig.read;
|
|
116
|
+
const timeoutId = setTimeout(() => controller.abort(), totalTimeout);
|
|
117
|
+
|
|
118
|
+
// Update signal for this attempt
|
|
119
|
+
const attemptOptions = { ...requestOptions, signal: controller.signal };
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const response = await globalThis.fetch!(requestUrl, attemptOptions as RequestInit);
|
|
123
|
+
clearTimeout(timeoutId);
|
|
124
|
+
|
|
125
|
+
// Handle HTTP errors
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
let responseText = '';
|
|
128
|
+
try {
|
|
129
|
+
const respAny: any = response as any;
|
|
130
|
+
if (typeof respAny.text === 'function') {
|
|
131
|
+
responseText = await respAny.text();
|
|
132
|
+
} else if (typeof respAny.json === 'function') {
|
|
133
|
+
// Fallback to JSON serialization if text() is not available on mocks
|
|
134
|
+
responseText = JSON.stringify(await respAny.json());
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// ignore parse errors, keep empty responseText
|
|
138
|
+
}
|
|
139
|
+
throw new HTTPError(response.status, response.statusText, responseText);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Parse response based on Content-Type with robust fallbacks for test mocks
|
|
143
|
+
let contentType = '';
|
|
144
|
+
const respAny: any = response as any;
|
|
145
|
+
const headersObj: any = respAny && respAny.headers;
|
|
146
|
+
if (headersObj) {
|
|
147
|
+
if (typeof headersObj.get === 'function') {
|
|
148
|
+
contentType = headersObj.get('content-type') || headersObj.get('Content-Type') || '';
|
|
149
|
+
} else if (typeof headersObj === 'object') {
|
|
150
|
+
contentType = headersObj['content-type'] || headersObj['Content-Type'] || '';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let responseData: unknown;
|
|
155
|
+
if (
|
|
156
|
+
contentType.includes('application/json') ||
|
|
157
|
+
(!contentType && typeof respAny.json === 'function')
|
|
158
|
+
) {
|
|
159
|
+
responseData = await response.json();
|
|
160
|
+
} else if (
|
|
161
|
+
contentType.includes('text/') ||
|
|
162
|
+
(!contentType && typeof respAny.text === 'function')
|
|
163
|
+
) {
|
|
164
|
+
responseData = await response.text();
|
|
165
|
+
} else if (typeof respAny.arrayBuffer === 'function') {
|
|
166
|
+
// For binary data or unknown types, return as ArrayBuffer
|
|
167
|
+
responseData = await response.arrayBuffer();
|
|
168
|
+
} else {
|
|
169
|
+
// Last resort: return the raw response object
|
|
170
|
+
responseData = response as unknown;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return responseData;
|
|
174
|
+
} catch (error: unknown) {
|
|
175
|
+
clearTimeout(timeoutId);
|
|
176
|
+
|
|
177
|
+
// Handle different types of errors
|
|
178
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
179
|
+
const totalTimeout = this.timeoutConfig.connect + this.timeoutConfig.read;
|
|
180
|
+
lastError = new TimeoutError(
|
|
181
|
+
`Request to ${requestUrl} timed out after ${totalTimeout}ms`
|
|
182
|
+
);
|
|
183
|
+
} else if (error instanceof HTTPError) {
|
|
184
|
+
// Distinguish retryable 5xx from non-retryable 4xx errors
|
|
185
|
+
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
186
|
+
// 4xx errors are client errors - don't retry
|
|
187
|
+
throw error;
|
|
188
|
+
} else if (error.statusCode >= 500 && error.statusCode < 600) {
|
|
189
|
+
// Retry 5xx errors only for idempotent methods (GET, HEAD, OPTIONS)
|
|
190
|
+
const methodUpper = method.toUpperCase();
|
|
191
|
+
const isIdempotent =
|
|
192
|
+
methodUpper === 'GET' || methodUpper === 'HEAD' || methodUpper === 'OPTIONS';
|
|
193
|
+
if (isIdempotent) {
|
|
194
|
+
lastError = error;
|
|
195
|
+
} else {
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
// Other HTTP errors - don't retry
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
} else if (
|
|
203
|
+
error instanceof Error &&
|
|
204
|
+
error.name === 'TypeError' &&
|
|
205
|
+
error.message.includes('fetch')
|
|
206
|
+
) {
|
|
207
|
+
lastError = new ConnectionError(requestUrl, error);
|
|
208
|
+
} else {
|
|
209
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Don't retry on the last attempt
|
|
213
|
+
if (attempt === this.maxRetries) {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Wait before retrying (exponential backoff)
|
|
218
|
+
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
|
|
219
|
+
await this._sleep(delay);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Ensure we always have an error to throw
|
|
224
|
+
if (!lastError) {
|
|
225
|
+
lastError = new Error(
|
|
226
|
+
`Request to ${requestUrl} failed after ${this.maxRetries + 1} attempts with no specific error`
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
throw lastError;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Build URL with query parameters.
|
|
234
|
+
* @private
|
|
235
|
+
*/
|
|
236
|
+
private _buildUrl(baseUrl: string, params?: Record<string, string | number | boolean>): string {
|
|
237
|
+
if (!params || Object.keys(params).length === 0) {
|
|
238
|
+
return baseUrl;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const url = new URL(baseUrl);
|
|
242
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
243
|
+
if (value !== null && value !== undefined) {
|
|
244
|
+
url.searchParams.append(key, String(value));
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return url.toString();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Sleep for the specified number of milliseconds.
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
private _sleep(ms: number): Promise<void> {
|
|
256
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Close the HTTP client and clean up resources.
|
|
261
|
+
*/
|
|
262
|
+
public async close(): Promise<void> {
|
|
263
|
+
this.closed = true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Alias for close() to match Python SDK naming.
|
|
268
|
+
*/
|
|
269
|
+
public async aclose(): Promise<void> {
|
|
270
|
+
await this.close();
|
|
271
|
+
}
|
|
272
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barndoor SDK - JavaScript client for the Barndoor Platform API.
|
|
3
|
+
*
|
|
4
|
+
* The Barndoor SDK provides a simple, async interface for interacting with
|
|
5
|
+
* the Barndoor platform, including:
|
|
6
|
+
*
|
|
7
|
+
* - User authentication and token management
|
|
8
|
+
* - MCP server discovery and connection
|
|
9
|
+
* - OAuth flow handling for third-party integrations
|
|
10
|
+
* - Agent credential exchange
|
|
11
|
+
*
|
|
12
|
+
* Quick Start
|
|
13
|
+
* -----------
|
|
14
|
+
* ```javascript
|
|
15
|
+
* import { BarndoorSDK } from '@barndoor/sdk';
|
|
16
|
+
*
|
|
17
|
+
* const sdk = new BarndoorSDK('https://api.barndoor.host', {
|
|
18
|
+
* token: 'your_token'
|
|
19
|
+
* });
|
|
20
|
+
* const servers = await sdk.listServers();
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* For interactive login:
|
|
24
|
+
* ```javascript
|
|
25
|
+
* import { loginInteractive } from '@barndoor/sdk';
|
|
26
|
+
*
|
|
27
|
+
* const sdk = await loginInteractive();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// Main SDK class
|
|
32
|
+
export { BarndoorSDK } from './client';
|
|
33
|
+
|
|
34
|
+
// Exception classes
|
|
35
|
+
export {
|
|
36
|
+
BarndoorError,
|
|
37
|
+
AuthenticationError,
|
|
38
|
+
TokenError,
|
|
39
|
+
TokenExpiredError,
|
|
40
|
+
TokenValidationError,
|
|
41
|
+
ConnectionError,
|
|
42
|
+
HTTPError,
|
|
43
|
+
ServerNotFoundError,
|
|
44
|
+
OAuthError,
|
|
45
|
+
ConfigurationError,
|
|
46
|
+
TimeoutError,
|
|
47
|
+
} from './exceptions';
|
|
48
|
+
|
|
49
|
+
// Data models
|
|
50
|
+
export { ServerSummary, ServerDetail, AgentToken } from './models';
|
|
51
|
+
|
|
52
|
+
// Quick-start helpers
|
|
53
|
+
export {
|
|
54
|
+
loginInteractive,
|
|
55
|
+
ensureServerConnected,
|
|
56
|
+
makeMcpConnectionParams,
|
|
57
|
+
makeMcpClient,
|
|
58
|
+
} from './quickstart';
|
|
59
|
+
|
|
60
|
+
// Authentication utilities
|
|
61
|
+
export {
|
|
62
|
+
PKCEManager,
|
|
63
|
+
startLocalCallbackServer,
|
|
64
|
+
loadUserToken,
|
|
65
|
+
saveUserToken,
|
|
66
|
+
clearCachedToken,
|
|
67
|
+
verifyJWTLocal,
|
|
68
|
+
JWTVerificationResult,
|
|
69
|
+
isTokenActive,
|
|
70
|
+
isTokenActiveWithRefresh,
|
|
71
|
+
validateToken,
|
|
72
|
+
TokenManager,
|
|
73
|
+
setTokenLogger,
|
|
74
|
+
} from './auth';
|
|
75
|
+
|
|
76
|
+
// Configuration
|
|
77
|
+
export {
|
|
78
|
+
BarndoorConfig,
|
|
79
|
+
getStaticConfig,
|
|
80
|
+
getDynamicConfig,
|
|
81
|
+
checkTokenOrganization,
|
|
82
|
+
hasOrganizationInfo,
|
|
83
|
+
isBrowser,
|
|
84
|
+
isNode,
|
|
85
|
+
} from './config';
|
|
86
|
+
|
|
87
|
+
// Logging
|
|
88
|
+
export { setLogger, getLogger, createScopedLogger, debug, info, warn, error } from './logging';
|
|
89
|
+
export type { Logger } from './logging';
|
|
90
|
+
|
|
91
|
+
// Version
|
|
92
|
+
export { version } from './version';
|
package/src/logging.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified logging system for the Barndoor SDK.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a centralized logging interface that can be configured
|
|
5
|
+
* by SDK consumers to integrate with their preferred logging systems.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Logger interface for SDK consumers to plug their own logger.
|
|
10
|
+
*/
|
|
11
|
+
export interface Logger {
|
|
12
|
+
debug(message: string, ...args: unknown[]): void;
|
|
13
|
+
info(message: string, ...args: unknown[]): void;
|
|
14
|
+
warn(message: string, ...args: unknown[]): void;
|
|
15
|
+
error(message: string, ...args: unknown[]): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default console logger implementation.
|
|
20
|
+
*/
|
|
21
|
+
const defaultLogger: Logger = {
|
|
22
|
+
debug: (message: string, ...args: unknown[]) => {
|
|
23
|
+
if (typeof console !== 'undefined' && console.debug) {
|
|
24
|
+
console.debug(message, ...args);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
info: (message: string, ...args: unknown[]) => {
|
|
28
|
+
if (typeof console !== 'undefined' && console.info) {
|
|
29
|
+
console.info(message, ...args);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
warn: (message: string, ...args: unknown[]) => {
|
|
33
|
+
if (typeof console !== 'undefined' && console.warn) {
|
|
34
|
+
console.warn(message, ...args);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
error: (message: string, ...args: unknown[]) => {
|
|
38
|
+
if (typeof console !== 'undefined' && console.error) {
|
|
39
|
+
console.error(message, ...args);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Global logger instance that can be configured
|
|
45
|
+
let _logger: Logger = defaultLogger;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Set a custom logger for the entire SDK.
|
|
49
|
+
* @param logger - Custom logger implementation
|
|
50
|
+
*/
|
|
51
|
+
export function setLogger(logger: Logger): void {
|
|
52
|
+
_logger = logger;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the current logger instance.
|
|
57
|
+
* @returns Current logger
|
|
58
|
+
*/
|
|
59
|
+
export function getLogger(): Logger {
|
|
60
|
+
return _logger;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create a scoped logger with a prefix for better organization.
|
|
65
|
+
* @param scope - Scope name (e.g., 'client', 'auth', 'http')
|
|
66
|
+
* @returns Scoped logger
|
|
67
|
+
*/
|
|
68
|
+
export function createScopedLogger(scope: string): Logger {
|
|
69
|
+
return {
|
|
70
|
+
debug: (message: string, ...args: unknown[]) => {
|
|
71
|
+
_logger.debug(`[${scope}] ${message}`, ...args);
|
|
72
|
+
},
|
|
73
|
+
info: (message: string, ...args: unknown[]) => {
|
|
74
|
+
_logger.info(`[${scope}] ${message}`, ...args);
|
|
75
|
+
},
|
|
76
|
+
warn: (message: string, ...args: unknown[]) => {
|
|
77
|
+
_logger.warn(`[${scope}] ${message}`, ...args);
|
|
78
|
+
},
|
|
79
|
+
error: (message: string, ...args: unknown[]) => {
|
|
80
|
+
_logger.error(`[${scope}] ${message}`, ...args);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Convenience function to log debug messages.
|
|
87
|
+
*/
|
|
88
|
+
export function debug(message: string, ...args: unknown[]): void {
|
|
89
|
+
_logger.debug(message, ...args);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convenience function to log info messages.
|
|
94
|
+
*/
|
|
95
|
+
export function info(message: string, ...args: unknown[]): void {
|
|
96
|
+
_logger.info(message, ...args);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convenience function to log warning messages.
|
|
101
|
+
*/
|
|
102
|
+
export function warn(message: string, ...args: unknown[]): void {
|
|
103
|
+
_logger.warn(message, ...args);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Convenience function to log error messages.
|
|
108
|
+
*/
|
|
109
|
+
export function error(message: string, ...args: unknown[]): void {
|
|
110
|
+
_logger.error(message, ...args);
|
|
111
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data models for the Barndoor SDK.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the data models used for API requests and responses,
|
|
5
|
+
* providing type safety and validation that mirrors the Python SDK's Pydantic models.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Connection status for MCP servers.
|
|
10
|
+
*/
|
|
11
|
+
export type ConnectionStatus = 'available' | 'pending' | 'connected';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Raw server data from API responses.
|
|
15
|
+
*/
|
|
16
|
+
export interface ServerSummaryData {
|
|
17
|
+
/** Unique identifier (UUID) for the server */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Human-readable name of the server */
|
|
20
|
+
name: string;
|
|
21
|
+
/** URL-friendly identifier used in API paths */
|
|
22
|
+
slug: string;
|
|
23
|
+
/** Third-party provider name (e.g., "github", "slack") */
|
|
24
|
+
provider?: string | null;
|
|
25
|
+
/** Current connection status */
|
|
26
|
+
connection_status: ConnectionStatus;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Summary information about an MCP server.
|
|
31
|
+
*
|
|
32
|
+
* Represents basic server information as returned by the list servers
|
|
33
|
+
* endpoint. This is a lightweight representation suitable for listing
|
|
34
|
+
* many servers at once.
|
|
35
|
+
*/
|
|
36
|
+
export class ServerSummary {
|
|
37
|
+
/** Unique identifier (UUID) for the server */
|
|
38
|
+
public readonly id: string;
|
|
39
|
+
/** Human-readable name of the server */
|
|
40
|
+
public readonly name: string;
|
|
41
|
+
/** URL-friendly identifier used in API paths */
|
|
42
|
+
public readonly slug: string;
|
|
43
|
+
/** Third-party provider name (e.g., "github", "slack") */
|
|
44
|
+
public readonly provider: string | null;
|
|
45
|
+
/** Current connection status */
|
|
46
|
+
public readonly connection_status: ConnectionStatus;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a new ServerSummary instance.
|
|
50
|
+
* @param data - Server data from API response
|
|
51
|
+
*/
|
|
52
|
+
constructor(data: ServerSummaryData) {
|
|
53
|
+
this.id = data.id;
|
|
54
|
+
this.name = data.name;
|
|
55
|
+
this.slug = data.slug;
|
|
56
|
+
this.provider = data.provider ?? null;
|
|
57
|
+
this.connection_status = data.connection_status;
|
|
58
|
+
|
|
59
|
+
// Validate required fields
|
|
60
|
+
if (!this.id || !this.name || !this.slug || !this.connection_status) {
|
|
61
|
+
throw new Error('ServerSummary missing required fields');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create a ServerSummary from API response data.
|
|
67
|
+
* @param data - Raw API response data
|
|
68
|
+
* @returns ServerSummary instance
|
|
69
|
+
*/
|
|
70
|
+
public static fromApiResponse(data: unknown): ServerSummary {
|
|
71
|
+
return new ServerSummary(data as ServerSummaryData);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Raw server detail data from API responses.
|
|
77
|
+
*/
|
|
78
|
+
export interface ServerDetailData extends ServerSummaryData {
|
|
79
|
+
/** MCP base URL from the server directory */
|
|
80
|
+
url?: string | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Detailed information about an MCP server.
|
|
85
|
+
*
|
|
86
|
+
* Extends ServerSummary with additional fields returned when fetching
|
|
87
|
+
* a single server's details.
|
|
88
|
+
*/
|
|
89
|
+
export class ServerDetail extends ServerSummary {
|
|
90
|
+
/** MCP base URL from the server directory */
|
|
91
|
+
public readonly url: string | null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a new ServerDetail instance.
|
|
95
|
+
* @param data - Server data from API response
|
|
96
|
+
*/
|
|
97
|
+
constructor(data: ServerDetailData) {
|
|
98
|
+
super(data);
|
|
99
|
+
this.url = data.url ?? null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create a ServerDetail from API response data.
|
|
104
|
+
* @param data - Raw API response data
|
|
105
|
+
* @returns ServerDetail instance
|
|
106
|
+
*/
|
|
107
|
+
public static override fromApiResponse(data: unknown): ServerDetail {
|
|
108
|
+
return new ServerDetail(data as ServerDetailData);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Raw agent token data from API responses.
|
|
114
|
+
*/
|
|
115
|
+
export interface AgentTokenData {
|
|
116
|
+
/** The agent access token to use for agent operations */
|
|
117
|
+
agent_token: string;
|
|
118
|
+
/** Token lifetime in seconds */
|
|
119
|
+
expires_in: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Response from the agent token exchange endpoint.
|
|
124
|
+
*
|
|
125
|
+
* Contains the agent access token and expiration information returned
|
|
126
|
+
* when exchanging client credentials.
|
|
127
|
+
*/
|
|
128
|
+
export class AgentToken {
|
|
129
|
+
/** The agent access token to use for agent operations */
|
|
130
|
+
public readonly agent_token: string;
|
|
131
|
+
/** Token lifetime in seconds */
|
|
132
|
+
public readonly expires_in: number;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Create a new AgentToken instance.
|
|
136
|
+
* @param data - Token data from API response
|
|
137
|
+
*/
|
|
138
|
+
constructor(data: AgentTokenData) {
|
|
139
|
+
this.agent_token = data.agent_token;
|
|
140
|
+
this.expires_in = data.expires_in;
|
|
141
|
+
|
|
142
|
+
// Validate required fields
|
|
143
|
+
if (!this.agent_token || typeof this.expires_in !== 'number') {
|
|
144
|
+
throw new Error('AgentToken missing required fields');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create an AgentToken from API response data.
|
|
150
|
+
* @param data - Raw API response data
|
|
151
|
+
* @returns AgentToken instance
|
|
152
|
+
*/
|
|
153
|
+
public static fromApiResponse(data: unknown): AgentToken {
|
|
154
|
+
return new AgentToken(data as AgentTokenData);
|
|
155
|
+
}
|
|
156
|
+
}
|