hornerosssp 0.1.0 → 0.3.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.
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli/index.ts
27
+ var import_commander7 = require("commander");
28
+ var import_chalk8 = __toESM(require("chalk"));
29
+
30
+ // src/cli/commands/login.ts
31
+ var import_commander = require("commander");
32
+ var import_chalk2 = __toESM(require("chalk"));
33
+ var import_inquirer = __toESM(require("inquirer"));
34
+ var import_open = __toESM(require("open"));
35
+
36
+ // src/cli/config.ts
37
+ var fs = __toESM(require("fs"));
38
+ var path = __toESM(require("path"));
39
+ var os = __toESM(require("os"));
40
+ var CONFIG_DIR = path.join(os.homedir(), ".hornerosssp");
41
+ var CONFIG_FILE = path.join(CONFIG_DIR, "userData.json");
42
+ function ensureConfigDir() {
43
+ if (!fs.existsSync(CONFIG_DIR)) {
44
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
45
+ }
46
+ }
47
+ function getUserData() {
48
+ try {
49
+ if (fs.existsSync(CONFIG_FILE)) {
50
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
51
+ return JSON.parse(content);
52
+ }
53
+ } catch {
54
+ }
55
+ return {};
56
+ }
57
+ function saveUserData(data) {
58
+ ensureConfigDir();
59
+ const existing = getUserData();
60
+ const merged = { ...existing, ...data };
61
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
62
+ }
63
+ function clearUserData() {
64
+ if (fs.existsSync(CONFIG_FILE)) {
65
+ fs.unlinkSync(CONFIG_FILE);
66
+ }
67
+ }
68
+ function getApiKey() {
69
+ return process.env.HORNEROS_API_KEY || getUserData().api_key;
70
+ }
71
+ function getBaseUrl() {
72
+ return process.env.HORNEROS_BASE_URL || getUserData().base_url || "http://localhost:3000";
73
+ }
74
+ function setCliConfig(apiKey, baseUrl) {
75
+ const data = { api_key: apiKey };
76
+ if (baseUrl) {
77
+ data.base_url = baseUrl;
78
+ }
79
+ saveUserData(data);
80
+ }
81
+
82
+ // src/cli/client.ts
83
+ var import_chalk = __toESM(require("chalk"));
84
+ var ApiClient = class {
85
+ constructor() {
86
+ this.baseUrl = getBaseUrl();
87
+ this.apiKey = getApiKey();
88
+ }
89
+ async fetch(path2, options = {}) {
90
+ const url = `${this.baseUrl}/api/v1${path2}`;
91
+ const headers = {
92
+ "Content-Type": "application/json",
93
+ "X-Source": "cli",
94
+ ...options.headers
95
+ };
96
+ if (this.apiKey) {
97
+ headers["X-Api-Key"] = this.apiKey;
98
+ }
99
+ const res = await globalThis.fetch(url, {
100
+ ...options,
101
+ headers
102
+ });
103
+ if (!res.ok) {
104
+ let body;
105
+ try {
106
+ body = await res.json();
107
+ } catch {
108
+ body = await res.text().catch(() => null);
109
+ }
110
+ const message = (body && typeof body === "object" && "error" in body ? body.error : null) || `HTTP ${res.status}`;
111
+ throw new Error(message);
112
+ }
113
+ if (res.status === 204) {
114
+ return void 0;
115
+ }
116
+ const json = await res.json();
117
+ return json.data !== void 0 ? json.data : json;
118
+ }
119
+ // CLI Auth endpoints
120
+ async generateCliSession() {
121
+ return this.fetch("/cli/session", { method: "POST" });
122
+ }
123
+ async verifyCliCode(key, code) {
124
+ return this.fetch(`/cli/verify?key=${encodeURIComponent(key)}&code=${encodeURIComponent(code)}`);
125
+ }
126
+ // User endpoints
127
+ async getUserInfo() {
128
+ return this.fetch("/auth/me");
129
+ }
130
+ // Apps/MCPs endpoints
131
+ async listApps() {
132
+ return this.fetch("/mcps");
133
+ }
134
+ async getApp(slug) {
135
+ return this.fetch(`/mcps/${encodeURIComponent(slug)}`);
136
+ }
137
+ // Connections endpoints
138
+ async listConnections() {
139
+ return this.fetch("/connections");
140
+ }
141
+ async getConnection(id) {
142
+ return this.fetch(`/connections/${encodeURIComponent(id)}`);
143
+ }
144
+ async initiateConnection(mcpSlug, params) {
145
+ return this.fetch("/connections", {
146
+ method: "POST",
147
+ body: JSON.stringify({
148
+ mcp_slug: mcpSlug,
149
+ ...params?.appName && { app_name: params.appName },
150
+ ...params?.userId && { user_id: params.userId }
151
+ })
152
+ });
153
+ }
154
+ async revokeConnection(id) {
155
+ return this.fetch(`/connections/${encodeURIComponent(id)}`, { method: "DELETE" });
156
+ }
157
+ };
158
+ function getClient() {
159
+ return new ApiClient();
160
+ }
161
+ function requireAuth() {
162
+ const apiKey = getApiKey();
163
+ if (!apiKey) {
164
+ console.log(import_chalk.default.red("You are not authenticated. Please run `hornerosssp login` to authenticate."));
165
+ process.exit(1);
166
+ }
167
+ }
168
+
169
+ // src/cli/commands/login.ts
170
+ var FRONTEND_BASE_URL = "http://localhost:3000";
171
+ var loginCommand = new import_commander.Command("login").description("Authenticate and login to HornerosSSP").option("-n, --no-browser", "Don't open browser, manually copy the link").option("-k, --api-key <key>", "Provide API key directly").option("-u, --base-url <url>", "Base URL of HornerosSSP server").action(async (options) => {
172
+ if (options.apiKey) {
173
+ setCliConfig(options.apiKey, options.baseUrl);
174
+ console.log(import_chalk2.default.green("\n API key saved successfully!\n"));
175
+ return;
176
+ }
177
+ const existingKey = getApiKey();
178
+ if (existingKey) {
179
+ console.log(import_chalk2.default.yellow("\n You are already authenticated!\n"));
180
+ const { shouldReauth } = await import_inquirer.default.prompt([{
181
+ type: "confirm",
182
+ name: "shouldReauth",
183
+ message: "Do you want to re-authenticate?",
184
+ default: false
185
+ }]);
186
+ if (!shouldReauth) {
187
+ return;
188
+ }
189
+ }
190
+ try {
191
+ const client = getClient();
192
+ console.log(import_chalk2.default.dim("\n Generating login session...\n"));
193
+ const session = await client.generateCliSession();
194
+ const cliKey = session.key;
195
+ const baseUrl = options.baseUrl || getBaseUrl() || FRONTEND_BASE_URL;
196
+ const loginUrl = `${baseUrl}/cli-auth?cliKey=${cliKey}`;
197
+ console.log(import_chalk2.default.bold(" Please login using the following link:\n"));
198
+ console.log(` ${import_chalk2.default.cyan(loginUrl)}
199
+ `);
200
+ if (options.browser !== false) {
201
+ console.log(import_chalk2.default.dim(" Opening browser...\n"));
202
+ await (0, import_open.default)(loginUrl);
203
+ }
204
+ const { authCode } = await import_inquirer.default.prompt([{
205
+ type: "input",
206
+ name: "authCode",
207
+ message: "Enter the authentication code:"
208
+ }]);
209
+ console.log(import_chalk2.default.dim("\n Verifying code...\n"));
210
+ const result = await client.verifyCliCode(cliKey, authCode);
211
+ setCliConfig(result.apiKey, options.baseUrl);
212
+ console.log(import_chalk2.default.green(" You are now authenticated and ready to use HornerosSSP!\n"));
213
+ } catch (error) {
214
+ const message = error instanceof Error ? error.message : "Unknown error";
215
+ console.log(import_chalk2.default.red(`
216
+ Login failed: ${message}
217
+ `));
218
+ process.exit(1);
219
+ }
220
+ });
221
+
222
+ // src/cli/commands/logout.ts
223
+ var import_commander2 = require("commander");
224
+ var import_chalk3 = __toESM(require("chalk"));
225
+ var logoutCommand = new import_commander2.Command("logout").description("Clear authentication and logout from HornerosSSP").action(() => {
226
+ clearUserData();
227
+ console.log(import_chalk3.default.yellow("\n You have been logged out from HornerosSSP.\n"));
228
+ });
229
+
230
+ // src/cli/commands/whoami.ts
231
+ var import_commander3 = require("commander");
232
+ var import_chalk4 = __toESM(require("chalk"));
233
+ var whoamiCommand = new import_commander3.Command("whoami").description("Show current user info").action(async () => {
234
+ requireAuth();
235
+ try {
236
+ const client = getClient();
237
+ const user = await client.getUserInfo();
238
+ console.log(import_chalk4.default.bold("\n Current User\n"));
239
+ console.log(` ${import_chalk4.default.cyan("ID:")} ${user.id}`);
240
+ console.log(` ${import_chalk4.default.cyan("Email:")} ${user.email}`);
241
+ if (user.name) {
242
+ console.log(` ${import_chalk4.default.cyan("Name:")} ${user.name}`);
243
+ }
244
+ console.log(` ${import_chalk4.default.cyan("Server:")} ${getBaseUrl()}`);
245
+ console.log();
246
+ } catch (error) {
247
+ const message = error instanceof Error ? error.message : "Unknown error";
248
+ console.log(import_chalk4.default.red(`
249
+ Failed to get user info: ${message}
250
+ `));
251
+ process.exit(1);
252
+ }
253
+ });
254
+
255
+ // src/cli/commands/apps.ts
256
+ var import_commander4 = require("commander");
257
+ var import_chalk5 = __toESM(require("chalk"));
258
+ var appsCommand = new import_commander4.Command("apps").description("List available MCPs/apps").option("-s, --search <query>", "Search apps by name").action(async (options) => {
259
+ requireAuth();
260
+ try {
261
+ const client = getClient();
262
+ let apps = await client.listApps();
263
+ if (options.search) {
264
+ const query = options.search.toLowerCase();
265
+ apps = apps.filter(
266
+ (app) => app.name.toLowerCase().includes(query) || app.slug.toLowerCase().includes(query) || app.description && app.description.toLowerCase().includes(query)
267
+ );
268
+ }
269
+ if (apps.length === 0) {
270
+ console.log(import_chalk5.default.yellow("\n No apps found.\n"));
271
+ return;
272
+ }
273
+ console.log(import_chalk5.default.bold(`
274
+ Available Apps (${apps.length})
275
+ `));
276
+ for (const app of apps) {
277
+ console.log(` ${import_chalk5.default.cyan(app.name)} ${import_chalk5.default.dim(`(${app.slug})`)}`);
278
+ if (app.description) {
279
+ console.log(` ${import_chalk5.default.dim(app.description)}`);
280
+ }
281
+ console.log(` ${import_chalk5.default.green(`${app.toolCount} tools`)} | ${import_chalk5.default.blue(`${app.activeConnections} connections`)}`);
282
+ console.log();
283
+ }
284
+ console.log(import_chalk5.default.dim(` Run ${import_chalk5.default.cyan("hornerosssp add <app-slug>")} to connect an app.
285
+ `));
286
+ } catch (error) {
287
+ const message = error instanceof Error ? error.message : "Unknown error";
288
+ console.log(import_chalk5.default.red(`
289
+ Failed to list apps: ${message}
290
+ `));
291
+ process.exit(1);
292
+ }
293
+ });
294
+
295
+ // src/cli/commands/add.ts
296
+ var import_commander5 = require("commander");
297
+ var import_chalk6 = __toESM(require("chalk"));
298
+ var import_inquirer2 = __toESM(require("inquirer"));
299
+ var import_open2 = __toESM(require("open"));
300
+ var addCommand = new import_commander5.Command("add").description("Connect a new app/MCP").argument("<app-slug>", "The slug of the app to connect (e.g., gmail, slack)").option("-n, --no-browser", "Don't open browser for OAuth").option("-l, --label <label>", "Label for this connection").option("-u, --user-id <userId>", "User ID for multi-tenant apps").action(async (appSlug, options) => {
301
+ requireAuth();
302
+ try {
303
+ const client = getClient();
304
+ console.log(import_chalk6.default.dim(`
305
+ Checking app "${appSlug}"...
306
+ `));
307
+ let app;
308
+ try {
309
+ app = await client.getApp(appSlug);
310
+ } catch {
311
+ console.log(import_chalk6.default.red(` App "${appSlug}" not found.
312
+ `));
313
+ console.log(import_chalk6.default.dim(` Run ${import_chalk6.default.cyan("hornerosssp apps")} to see available apps.
314
+ `));
315
+ process.exit(1);
316
+ }
317
+ console.log(` Connecting ${import_chalk6.default.cyan(app.name)}...
318
+ `);
319
+ const connections = await client.listConnections();
320
+ const existingConnection = connections.find((c) => c.mcpSlug === appSlug && c.status === "active");
321
+ if (existingConnection) {
322
+ const { shouldReconnect } = await import_inquirer2.default.prompt([{
323
+ type: "confirm",
324
+ name: "shouldReconnect",
325
+ message: `You already have an active connection to ${app.name}. Create a new one?`,
326
+ default: false
327
+ }]);
328
+ if (!shouldReconnect) {
329
+ console.log(import_chalk6.default.yellow("\n Connection cancelled.\n"));
330
+ return;
331
+ }
332
+ }
333
+ const connectionRequest = await client.initiateConnection(appSlug, {
334
+ appName: options.label,
335
+ userId: options.userId
336
+ });
337
+ if (connectionRequest.redirectUrl) {
338
+ console.log(import_chalk6.default.bold(" Please authorize the connection:\n"));
339
+ console.log(` ${import_chalk6.default.cyan(connectionRequest.redirectUrl)}
340
+ `);
341
+ if (options.browser !== false) {
342
+ console.log(import_chalk6.default.dim(" Opening browser...\n"));
343
+ await (0, import_open2.default)(connectionRequest.redirectUrl);
344
+ }
345
+ console.log(import_chalk6.default.dim(" Waiting for authorization..."));
346
+ const timeout = 12e4;
347
+ const pollInterval = 3e3;
348
+ const startTime = Date.now();
349
+ while (Date.now() - startTime < timeout) {
350
+ await sleep(pollInterval);
351
+ try {
352
+ const connection = await client.getConnection(connectionRequest.id);
353
+ if (connection.status === "active") {
354
+ console.log(import_chalk6.default.green(`
355
+ Successfully connected to ${app.name}!
356
+ `));
357
+ console.log(` ${import_chalk6.default.cyan("Connection ID:")} ${connection.id}`);
358
+ console.log(` ${import_chalk6.default.cyan("MCP URL:")} ${connection.mcpUrl}
359
+ `);
360
+ return;
361
+ }
362
+ } catch {
363
+ }
364
+ process.stdout.write(".");
365
+ }
366
+ console.log(import_chalk6.default.red("\n\n Connection timed out. Please try again.\n"));
367
+ process.exit(1);
368
+ } else {
369
+ console.log(import_chalk6.default.green(`
370
+ Successfully connected to ${app.name}!
371
+ `));
372
+ console.log(` ${import_chalk6.default.cyan("Connection ID:")} ${connectionRequest.id}`);
373
+ if (connectionRequest.mcpUrl) {
374
+ console.log(` ${import_chalk6.default.cyan("MCP URL:")} ${connectionRequest.mcpUrl}
375
+ `);
376
+ }
377
+ }
378
+ } catch (error) {
379
+ const message = error instanceof Error ? error.message : "Unknown error";
380
+ console.log(import_chalk6.default.red(`
381
+ Failed to connect app: ${message}
382
+ `));
383
+ process.exit(1);
384
+ }
385
+ });
386
+ function sleep(ms) {
387
+ return new Promise((resolve) => setTimeout(resolve, ms));
388
+ }
389
+
390
+ // src/cli/commands/connections.ts
391
+ var import_commander6 = require("commander");
392
+ var import_chalk7 = __toESM(require("chalk"));
393
+ var import_inquirer3 = __toESM(require("inquirer"));
394
+ var connectionsCommand = new import_commander6.Command("connections").description("Manage your connections").action(async () => {
395
+ requireAuth();
396
+ try {
397
+ const client = getClient();
398
+ const connections = await client.listConnections();
399
+ if (connections.length === 0) {
400
+ console.log(import_chalk7.default.yellow("\n No connections found.\n"));
401
+ console.log(import_chalk7.default.dim(` Run ${import_chalk7.default.cyan("hornerosssp add <app>")} to connect an app.
402
+ `));
403
+ return;
404
+ }
405
+ console.log(import_chalk7.default.bold(`
406
+ Your Connections (${connections.length})
407
+ `));
408
+ for (const conn of connections) {
409
+ const statusColor = conn.status === "active" ? import_chalk7.default.green : import_chalk7.default.red;
410
+ const statusIcon = conn.status === "active" ? "\u25CF" : "\u25CB";
411
+ console.log(` ${statusColor(statusIcon)} ${import_chalk7.default.cyan(conn.mcpName)} ${import_chalk7.default.dim(`(${conn.mcpSlug})`)}`);
412
+ console.log(` ${import_chalk7.default.dim("ID:")} ${conn.id}`);
413
+ if (conn.appName) {
414
+ console.log(` ${import_chalk7.default.dim("Label:")} ${conn.appName}`);
415
+ }
416
+ console.log(` ${import_chalk7.default.dim("Status:")} ${statusColor(conn.status)}`);
417
+ console.log(` ${import_chalk7.default.dim("Created:")} ${new Date(conn.createdAt).toLocaleDateString()}`);
418
+ if (conn.lastUsedAt) {
419
+ console.log(` ${import_chalk7.default.dim("Last used:")} ${new Date(conn.lastUsedAt).toLocaleDateString()}`);
420
+ }
421
+ console.log();
422
+ }
423
+ } catch (error) {
424
+ const message = error instanceof Error ? error.message : "Unknown error";
425
+ console.log(import_chalk7.default.red(`
426
+ Failed to list connections: ${message}
427
+ `));
428
+ process.exit(1);
429
+ }
430
+ });
431
+ connectionsCommand.command("get <id>").description("Get details of a specific connection").action(async (id) => {
432
+ requireAuth();
433
+ try {
434
+ const client = getClient();
435
+ const conn = await client.getConnection(id);
436
+ const statusColor = conn.status === "active" ? import_chalk7.default.green : import_chalk7.default.red;
437
+ console.log(import_chalk7.default.bold(`
438
+ Connection Details
439
+ `));
440
+ console.log(` ${import_chalk7.default.cyan("ID:")} ${conn.id}`);
441
+ console.log(` ${import_chalk7.default.cyan("App:")} ${conn.mcpName} (${conn.mcpSlug})`);
442
+ console.log(` ${import_chalk7.default.cyan("Status:")} ${statusColor(conn.status)}`);
443
+ if (conn.appName) {
444
+ console.log(` ${import_chalk7.default.cyan("Label:")} ${conn.appName}`);
445
+ }
446
+ if (conn.userId) {
447
+ console.log(` ${import_chalk7.default.cyan("User ID:")} ${conn.userId}`);
448
+ }
449
+ console.log(` ${import_chalk7.default.cyan("MCP URL:")} ${conn.mcpUrl}`);
450
+ console.log(` ${import_chalk7.default.cyan("Token:")} ${conn.token.substring(0, 20)}...`);
451
+ console.log(` ${import_chalk7.default.cyan("Created:")} ${new Date(conn.createdAt).toLocaleString()}`);
452
+ if (conn.lastUsedAt) {
453
+ console.log(` ${import_chalk7.default.cyan("Last used:")} ${new Date(conn.lastUsedAt).toLocaleString()}`);
454
+ }
455
+ if (conn.expiresAt) {
456
+ console.log(` ${import_chalk7.default.cyan("Expires:")} ${new Date(conn.expiresAt).toLocaleString()}`);
457
+ }
458
+ console.log();
459
+ } catch (error) {
460
+ const message = error instanceof Error ? error.message : "Unknown error";
461
+ console.log(import_chalk7.default.red(`
462
+ Failed to get connection: ${message}
463
+ `));
464
+ process.exit(1);
465
+ }
466
+ });
467
+ connectionsCommand.command("revoke <id>").description("Revoke a connection").option("-f, --force", "Skip confirmation").action(async (id, options) => {
468
+ requireAuth();
469
+ try {
470
+ const client = getClient();
471
+ const conn = await client.getConnection(id);
472
+ if (!options.force) {
473
+ const { confirm } = await import_inquirer3.default.prompt([{
474
+ type: "confirm",
475
+ name: "confirm",
476
+ message: `Are you sure you want to revoke the connection to ${conn.mcpName}?`,
477
+ default: false
478
+ }]);
479
+ if (!confirm) {
480
+ console.log(import_chalk7.default.yellow("\n Revoke cancelled.\n"));
481
+ return;
482
+ }
483
+ }
484
+ await client.revokeConnection(id);
485
+ console.log(import_chalk7.default.green(`
486
+ Connection to ${conn.mcpName} has been revoked.
487
+ `));
488
+ } catch (error) {
489
+ const message = error instanceof Error ? error.message : "Unknown error";
490
+ console.log(import_chalk7.default.red(`
491
+ Failed to revoke connection: ${message}
492
+ `));
493
+ process.exit(1);
494
+ }
495
+ });
496
+
497
+ // src/cli/index.ts
498
+ var program = new import_commander7.Command();
499
+ program.name("hornerosssp").description("CLI for HornerosSSP - Connect MCPs to any app").version("0.3.0");
500
+ program.addCommand(loginCommand);
501
+ program.addCommand(logoutCommand);
502
+ program.addCommand(whoamiCommand);
503
+ program.addCommand(appsCommand);
504
+ program.addCommand(addCommand);
505
+ program.addCommand(connectionsCommand);
506
+ program.on("command:*", () => {
507
+ console.error(import_chalk8.default.red(`
508
+ Unknown command: ${program.args.join(" ")}`));
509
+ console.log(`Run ${import_chalk8.default.cyan("hornerosssp --help")} to see available commands.
510
+ `);
511
+ process.exit(1);
512
+ });
513
+ program.parse(process.argv);
514
+ if (!process.argv.slice(2).length) {
515
+ console.log(import_chalk8.default.bold("\n HornerosSSP CLI\n"));
516
+ console.log(" Connect MCPs to any application.\n");
517
+ console.log(import_chalk8.default.dim(" Commands:"));
518
+ console.log(` ${import_chalk8.default.cyan("login")} Authenticate with HornerosSSP`);
519
+ console.log(` ${import_chalk8.default.cyan("logout")} Remove stored credentials`);
520
+ console.log(` ${import_chalk8.default.cyan("whoami")} Show current user info`);
521
+ console.log(` ${import_chalk8.default.cyan("apps")} List available MCPs`);
522
+ console.log(` ${import_chalk8.default.cyan("add")} Connect a new app (OAuth flow)`);
523
+ console.log(` ${import_chalk8.default.cyan("connections")} Manage your connections
524
+ `);
525
+ console.log(` Run ${import_chalk8.default.cyan("hornerosssp <command> --help")} for more info.
526
+ `);
527
+ }
package/dist/index.d.mts CHANGED
@@ -66,7 +66,12 @@ interface ConnectionData {
66
66
  data: Record<string, string>;
67
67
  }
68
68
  interface HornerosSSPConfig {
69
- baseUrl: string;
69
+ /** API key for authentication. Falls back to HORNEROS_API_KEY env var. */
70
+ apiKey?: string;
71
+ /** Base URL of the HornerosSSP server. Falls back to HORNEROS_BASE_URL env var. */
72
+ baseUrl?: string;
73
+ /** Runtime identifier sent with every request (e.g. "node", "vercel"). */
74
+ runtime?: string;
70
75
  }
71
76
  interface ApiResponse<T> {
72
77
  data: T;
@@ -119,7 +124,9 @@ declare class HornerosSSP {
119
124
  readonly connections: Connections;
120
125
  readonly tools: Tools;
121
126
  private readonly baseUrl;
122
- constructor(config: HornerosSSPConfig);
127
+ private readonly apiKey;
128
+ private readonly runtime;
129
+ constructor(config?: HornerosSSPConfig);
123
130
  /** @internal */
124
131
  fetch<T>(path: string, options?: RequestInit): Promise<T>;
125
132
  }
@@ -143,10 +150,38 @@ declare class AuthScheme {
143
150
  static GoogleLogin(): ConnectionData;
144
151
  }
145
152
 
153
+ declare const HORNEROS_SDK_ERROR_CODES: {
154
+ readonly BACKEND: {
155
+ readonly NOT_FOUND: "BACKEND::NOT_FOUND";
156
+ readonly RATE_LIMIT: "BACKEND::RATE_LIMIT";
157
+ readonly BAD_REQUEST: "BACKEND::BAD_REQUEST";
158
+ readonly UNAUTHORIZED: "BACKEND::UNAUTHORIZED";
159
+ readonly SERVER_ERROR: "BACKEND::SERVER_ERROR";
160
+ readonly SERVER_UNAVAILABLE: "BACKEND::SERVER_UNAVAILABLE";
161
+ readonly UNKNOWN: "BACKEND::UNKNOWN";
162
+ };
163
+ readonly COMMON: {
164
+ readonly API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE";
165
+ readonly BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE";
166
+ readonly UNKNOWN: "COMMON::UNKNOWN";
167
+ readonly INVALID_PARAMS: "COMMON::INVALID_PARAMS";
168
+ };
169
+ readonly SDK: {
170
+ readonly NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT";
171
+ readonly CONNECTION_TIMEOUT: "SDK::CONNECTION_TIMEOUT";
172
+ readonly INVALID_PARAMETER: "SDK::INVALID_PARAMETER";
173
+ };
174
+ };
146
175
  declare class HornerosError extends Error {
176
+ readonly errCode: string;
147
177
  readonly statusCode: number;
148
178
  readonly body: unknown;
149
- constructor(message: string, statusCode: number, body?: unknown);
179
+ readonly description?: string;
180
+ readonly possibleFix?: string;
181
+ readonly errorId: string;
182
+ readonly timestamp: string;
183
+ constructor(errCode: string, message: string, statusCode: number, body?: unknown, description?: string, possibleFix?: string);
184
+ toJSON(): Record<string, unknown>;
150
185
  }
151
186
  declare class NotFoundError extends HornerosError {
152
187
  constructor(message: string, body?: unknown);
@@ -158,4 +193,4 @@ declare class ConnectionTimeoutError extends HornerosError {
158
193
  constructor(message?: string);
159
194
  }
160
195
 
161
- export { type ApiError, type ApiResponse, AuthScheme, type ConnectionData, type ConnectionInfo, ConnectionRequest, type ConnectionRequestData, ConnectionTimeoutError, Connections, type ExecuteToolParams, HornerosError, HornerosSSP, type HornerosSSPConfig, type InitiateConnectionParams, type McpDetail, type McpInfo, Mcps, NotFoundError, type ToolDefinition, type ToolResult, Tools, ValidationError };
196
+ export { type ApiError, type ApiResponse, AuthScheme, type ConnectionData, type ConnectionInfo, ConnectionRequest, type ConnectionRequestData, ConnectionTimeoutError, Connections, type ExecuteToolParams, HORNEROS_SDK_ERROR_CODES, HornerosError, HornerosSSP, type HornerosSSPConfig, type InitiateConnectionParams, type McpDetail, type McpInfo, Mcps, NotFoundError, type ToolDefinition, type ToolResult, Tools, ValidationError };
package/dist/index.d.ts CHANGED
@@ -66,7 +66,12 @@ interface ConnectionData {
66
66
  data: Record<string, string>;
67
67
  }
68
68
  interface HornerosSSPConfig {
69
- baseUrl: string;
69
+ /** API key for authentication. Falls back to HORNEROS_API_KEY env var. */
70
+ apiKey?: string;
71
+ /** Base URL of the HornerosSSP server. Falls back to HORNEROS_BASE_URL env var. */
72
+ baseUrl?: string;
73
+ /** Runtime identifier sent with every request (e.g. "node", "vercel"). */
74
+ runtime?: string;
70
75
  }
71
76
  interface ApiResponse<T> {
72
77
  data: T;
@@ -119,7 +124,9 @@ declare class HornerosSSP {
119
124
  readonly connections: Connections;
120
125
  readonly tools: Tools;
121
126
  private readonly baseUrl;
122
- constructor(config: HornerosSSPConfig);
127
+ private readonly apiKey;
128
+ private readonly runtime;
129
+ constructor(config?: HornerosSSPConfig);
123
130
  /** @internal */
124
131
  fetch<T>(path: string, options?: RequestInit): Promise<T>;
125
132
  }
@@ -143,10 +150,38 @@ declare class AuthScheme {
143
150
  static GoogleLogin(): ConnectionData;
144
151
  }
145
152
 
153
+ declare const HORNEROS_SDK_ERROR_CODES: {
154
+ readonly BACKEND: {
155
+ readonly NOT_FOUND: "BACKEND::NOT_FOUND";
156
+ readonly RATE_LIMIT: "BACKEND::RATE_LIMIT";
157
+ readonly BAD_REQUEST: "BACKEND::BAD_REQUEST";
158
+ readonly UNAUTHORIZED: "BACKEND::UNAUTHORIZED";
159
+ readonly SERVER_ERROR: "BACKEND::SERVER_ERROR";
160
+ readonly SERVER_UNAVAILABLE: "BACKEND::SERVER_UNAVAILABLE";
161
+ readonly UNKNOWN: "BACKEND::UNKNOWN";
162
+ };
163
+ readonly COMMON: {
164
+ readonly API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE";
165
+ readonly BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE";
166
+ readonly UNKNOWN: "COMMON::UNKNOWN";
167
+ readonly INVALID_PARAMS: "COMMON::INVALID_PARAMS";
168
+ };
169
+ readonly SDK: {
170
+ readonly NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT";
171
+ readonly CONNECTION_TIMEOUT: "SDK::CONNECTION_TIMEOUT";
172
+ readonly INVALID_PARAMETER: "SDK::INVALID_PARAMETER";
173
+ };
174
+ };
146
175
  declare class HornerosError extends Error {
176
+ readonly errCode: string;
147
177
  readonly statusCode: number;
148
178
  readonly body: unknown;
149
- constructor(message: string, statusCode: number, body?: unknown);
179
+ readonly description?: string;
180
+ readonly possibleFix?: string;
181
+ readonly errorId: string;
182
+ readonly timestamp: string;
183
+ constructor(errCode: string, message: string, statusCode: number, body?: unknown, description?: string, possibleFix?: string);
184
+ toJSON(): Record<string, unknown>;
150
185
  }
151
186
  declare class NotFoundError extends HornerosError {
152
187
  constructor(message: string, body?: unknown);
@@ -158,4 +193,4 @@ declare class ConnectionTimeoutError extends HornerosError {
158
193
  constructor(message?: string);
159
194
  }
160
195
 
161
- export { type ApiError, type ApiResponse, AuthScheme, type ConnectionData, type ConnectionInfo, ConnectionRequest, type ConnectionRequestData, ConnectionTimeoutError, Connections, type ExecuteToolParams, HornerosError, HornerosSSP, type HornerosSSPConfig, type InitiateConnectionParams, type McpDetail, type McpInfo, Mcps, NotFoundError, type ToolDefinition, type ToolResult, Tools, ValidationError };
196
+ export { type ApiError, type ApiResponse, AuthScheme, type ConnectionData, type ConnectionInfo, ConnectionRequest, type ConnectionRequestData, ConnectionTimeoutError, Connections, type ExecuteToolParams, HORNEROS_SDK_ERROR_CODES, HornerosError, HornerosSSP, type HornerosSSPConfig, type InitiateConnectionParams, type McpDetail, type McpInfo, Mcps, NotFoundError, type ToolDefinition, type ToolResult, Tools, ValidationError };
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  ConnectionRequest: () => ConnectionRequest,
25
25
  ConnectionTimeoutError: () => ConnectionTimeoutError,
26
26
  Connections: () => Connections,
27
+ HORNEROS_SDK_ERROR_CODES: () => HORNEROS_SDK_ERROR_CODES,
27
28
  HornerosError: () => HornerosError,
28
29
  HornerosSSP: () => HornerosSSP,
29
30
  Mcps: () => Mcps,
@@ -34,29 +35,77 @@ __export(index_exports, {
34
35
  module.exports = __toCommonJS(index_exports);
35
36
 
36
37
  // src/errors.ts
38
+ var HORNEROS_SDK_ERROR_CODES = {
39
+ BACKEND: {
40
+ NOT_FOUND: "BACKEND::NOT_FOUND",
41
+ RATE_LIMIT: "BACKEND::RATE_LIMIT",
42
+ BAD_REQUEST: "BACKEND::BAD_REQUEST",
43
+ UNAUTHORIZED: "BACKEND::UNAUTHORIZED",
44
+ SERVER_ERROR: "BACKEND::SERVER_ERROR",
45
+ SERVER_UNAVAILABLE: "BACKEND::SERVER_UNAVAILABLE",
46
+ UNKNOWN: "BACKEND::UNKNOWN"
47
+ },
48
+ COMMON: {
49
+ API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE",
50
+ BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE",
51
+ UNKNOWN: "COMMON::UNKNOWN",
52
+ INVALID_PARAMS: "COMMON::INVALID_PARAMS"
53
+ },
54
+ SDK: {
55
+ NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT",
56
+ CONNECTION_TIMEOUT: "SDK::CONNECTION_TIMEOUT",
57
+ INVALID_PARAMETER: "SDK::INVALID_PARAMETER"
58
+ }
59
+ };
60
+ var errorCounter = 0;
37
61
  var HornerosError = class extends Error {
38
- constructor(message, statusCode, body) {
62
+ constructor(errCode, message, statusCode, body, description, possibleFix) {
39
63
  super(message);
40
64
  this.name = "HornerosError";
65
+ this.errCode = errCode;
41
66
  this.statusCode = statusCode;
42
67
  this.body = body;
68
+ this.description = description;
69
+ this.possibleFix = possibleFix;
70
+ this.errorId = `horneros_${Date.now()}_${++errorCounter}`;
71
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
72
+ }
73
+ toJSON() {
74
+ return {
75
+ name: this.name,
76
+ errCode: this.errCode,
77
+ message: this.message,
78
+ statusCode: this.statusCode,
79
+ description: this.description,
80
+ possibleFix: this.possibleFix,
81
+ errorId: this.errorId,
82
+ timestamp: this.timestamp,
83
+ body: this.body
84
+ };
43
85
  }
44
86
  };
45
87
  var NotFoundError = class extends HornerosError {
46
88
  constructor(message, body) {
47
- super(message, 404, body);
89
+ super(HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND, message, 404, body);
48
90
  this.name = "NotFoundError";
49
91
  }
50
92
  };
51
93
  var ValidationError = class extends HornerosError {
52
94
  constructor(message, body) {
53
- super(message, 400, body);
95
+ super(HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST, message, 400, body);
54
96
  this.name = "ValidationError";
55
97
  }
56
98
  };
57
99
  var ConnectionTimeoutError = class extends HornerosError {
58
100
  constructor(message = "Connection timed out waiting for activation") {
59
- super(message, 408);
101
+ super(
102
+ HORNEROS_SDK_ERROR_CODES.SDK.CONNECTION_TIMEOUT,
103
+ message,
104
+ 408,
105
+ void 0,
106
+ "The connection did not become active within the timeout period.",
107
+ "Increase the timeout value or check that the user completed the authentication flow."
108
+ );
60
109
  this.name = "ConnectionTimeoutError";
61
110
  }
62
111
  };
@@ -186,9 +235,35 @@ var Tools = class {
186
235
  };
187
236
 
188
237
  // src/client.ts
238
+ function getEnvVariable(name) {
239
+ if (typeof process !== "undefined" && process.env) {
240
+ return process.env[name];
241
+ }
242
+ return void 0;
243
+ }
244
+ var DEFAULT_BASE_URL = "http://localhost:3000";
245
+ function resolveConfig(config) {
246
+ const baseUrl = config?.baseUrl || getEnvVariable("HORNEROS_BASE_URL") || DEFAULT_BASE_URL;
247
+ const apiKey = config?.apiKey || getEnvVariable("HORNEROS_API_KEY") || "";
248
+ const runtime = config?.runtime || getEnvVariable("HORNEROS_RUNTIME") || "";
249
+ return { baseUrl: baseUrl.replace(/\/+$/, ""), apiKey, runtime };
250
+ }
189
251
  var HornerosSSP = class {
190
252
  constructor(config) {
191
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
253
+ const resolved = resolveConfig(config);
254
+ if (!resolved.apiKey) {
255
+ throw new HornerosError(
256
+ HORNEROS_SDK_ERROR_CODES.COMMON.API_KEY_UNAVAILABLE,
257
+ "\u{1F511} API Key is not provided",
258
+ 401,
259
+ void 0,
260
+ "You need to provide an API key in the constructor or as the environment variable HORNEROS_API_KEY.",
261
+ 'Provide a valid API key: new HornerosSSP({ apiKey: "hsp_xxx" }) or set HORNEROS_API_KEY in your environment.'
262
+ );
263
+ }
264
+ this.baseUrl = resolved.baseUrl;
265
+ this.apiKey = resolved.apiKey;
266
+ this.runtime = resolved.runtime;
192
267
  this.mcps = new Mcps(this);
193
268
  this.connections = new Connections(this);
194
269
  this.tools = new Tools(this);
@@ -198,6 +273,9 @@ var HornerosSSP = class {
198
273
  const url = `${this.baseUrl}/api/v1${path}`;
199
274
  const headers = {
200
275
  "Content-Type": "application/json",
276
+ "X-Api-Key": this.apiKey,
277
+ "X-Source": "js_sdk",
278
+ "X-Runtime": this.runtime,
201
279
  ...options.headers
202
280
  };
203
281
  const res = await globalThis.fetch(url, {
@@ -212,7 +290,8 @@ var HornerosSSP = class {
212
290
  body = await res.text().catch(() => null);
213
291
  }
214
292
  const message = (body && typeof body === "object" && "error" in body ? body.error : null) || `HTTP ${res.status}`;
215
- throw new HornerosError(message, res.status, body);
293
+ const errCode = res.status === 404 ? HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND : res.status === 401 ? HORNEROS_SDK_ERROR_CODES.BACKEND.UNAUTHORIZED : res.status === 429 ? HORNEROS_SDK_ERROR_CODES.BACKEND.RATE_LIMIT : res.status === 400 ? HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST : res.status >= 500 ? HORNEROS_SDK_ERROR_CODES.BACKEND.SERVER_ERROR : HORNEROS_SDK_ERROR_CODES.BACKEND.UNKNOWN;
294
+ throw new HornerosError(errCode, message, res.status, body);
216
295
  }
217
296
  if (res.status === 204) {
218
297
  return void 0;
@@ -248,6 +327,7 @@ var AuthScheme = class {
248
327
  ConnectionRequest,
249
328
  ConnectionTimeoutError,
250
329
  Connections,
330
+ HORNEROS_SDK_ERROR_CODES,
251
331
  HornerosError,
252
332
  HornerosSSP,
253
333
  Mcps,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/mcps.ts","../src/connections.ts","../src/tools.ts","../src/client.ts","../src/auth-scheme.ts"],"sourcesContent":["export { HornerosSSP } from \"./client\";\nexport { AuthScheme } from \"./auth-scheme\";\nexport { Mcps } from \"./mcps\";\nexport { Connections, ConnectionRequest } from \"./connections\";\nexport { Tools } from \"./tools\";\n\n// Errors\nexport {\n HornerosError,\n NotFoundError,\n ValidationError,\n ConnectionTimeoutError,\n} from \"./errors\";\n\n// Types\nexport type {\n HornerosSSPConfig,\n McpInfo,\n McpDetail,\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ConnectionData,\n ApiResponse,\n ApiError,\n} from \"./types\";\n","export class HornerosError extends Error {\n public readonly statusCode: number;\n public readonly body: unknown;\n\n constructor(message: string, statusCode: number, body?: unknown) {\n super(message);\n this.name = \"HornerosError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n\nexport class NotFoundError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(message, 404, body);\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(message, 400, body);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ConnectionTimeoutError extends HornerosError {\n constructor(message = \"Connection timed out waiting for activation\") {\n super(message, 408);\n this.name = \"ConnectionTimeoutError\";\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type { McpInfo, McpDetail, ApiResponse } from \"./types\";\n\nexport class Mcps {\n constructor(private client: HornerosSSP) {}\n\n async list(): Promise<McpInfo[]> {\n const res = await this.client.fetch<ApiResponse<McpInfo[]>>(\"/mcps\");\n return res.data;\n }\n\n async get(slug: string): Promise<McpDetail> {\n const res = await this.client.fetch<ApiResponse<McpDetail>>(\n `/mcps/${encodeURIComponent(slug)}`\n );\n return res.data;\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ApiResponse,\n} from \"./types\";\nimport { ConnectionTimeoutError } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpUrl: string | null;\n public readonly token: string | null;\n public readonly redirectUrl: string | null;\n public readonly status: \"active\" | \"pending\";\n\n constructor(\n private client: HornerosSSP,\n data: ConnectionRequestData\n ) {\n this.id = data.id;\n this.mcpUrl = data.mcpUrl;\n this.token = data.token;\n this.redirectUrl = data.redirectUrl;\n this.status = data.status;\n }\n\n /**\n * Polls the connection until it becomes active.\n * Useful for OAuth/interactive flows where the user needs to\n * complete authentication in a browser.\n * @param timeout Max wait time in ms (default: 120000 = 2 min)\n */\n async waitForConnection(timeout = 120_000): Promise<ConnectionInfo> {\n if (this.status === \"active\") {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n return res.data;\n }\n\n const start = Date.now();\n const interval = 2000;\n\n while (Date.now() - start < timeout) {\n await sleep(interval);\n try {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n if (res.data.status === \"active\") {\n return res.data;\n }\n } catch {\n // Connection not yet created, keep polling\n }\n }\n\n throw new ConnectionTimeoutError();\n }\n}\n\nexport class Connections {\n constructor(private client: HornerosSSP) {}\n\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n };\n\n if (params.appName) body.app_name = params.appName;\n if (params.userId) body.user_id = params.userId;\n if (params.credentials) body.credentials = params.credentials;\n if (params.authScheme) body.auth_scheme = params.authScheme;\n\n const res = await this.client.fetch<ApiResponse<ConnectionRequestData>>(\n \"/connections\",\n { method: \"POST\", body: JSON.stringify(body) }\n );\n\n return new ConnectionRequest(this.client, res.data);\n }\n\n async list(): Promise<ConnectionInfo[]> {\n const res =\n await this.client.fetch<ApiResponse<ConnectionInfo[]>>(\"/connections\");\n return res.data;\n }\n\n async get(id: string): Promise<ConnectionInfo> {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(id)}`\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.fetch<void>(\n `/connections/${encodeURIComponent(id)}`,\n { method: \"DELETE\" }\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ApiResponse,\n} from \"./types\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n async list(mcpSlug: string): Promise<ToolDefinition[]> {\n const res = await this.client.fetch<ApiResponse<ToolDefinition[]>>(\n `/mcps/${encodeURIComponent(mcpSlug)}/tools`\n );\n return res.data;\n }\n\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify({\n mcp_slug: params.mcpSlug,\n connection_id: params.connectionId,\n tool_name: params.toolName,\n arguments: params.arguments,\n }),\n }\n );\n return res.data;\n }\n}\n","import type { HornerosSSPConfig } from \"./types\";\nimport { HornerosError } from \"./errors\";\nimport { Mcps } from \"./mcps\";\nimport { Connections } from \"./connections\";\nimport { Tools } from \"./tools\";\n\nexport class HornerosSSP {\n public readonly mcps: Mcps;\n public readonly connections: Connections;\n public readonly tools: Tools;\n\n private readonly baseUrl: string;\n\n constructor(config: HornerosSSPConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/+$/, \"\");\n\n this.mcps = new Mcps(this);\n this.connections = new Connections(this);\n this.tools = new Tools(this);\n }\n\n /** @internal */\n async fetch<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}/api/v1${path}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n\n const res = await globalThis.fetch(url, {\n ...options,\n headers,\n });\n\n if (!res.ok) {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = await res.text().catch(() => null);\n }\n const message =\n (body && typeof body === \"object\" && \"error\" in body\n ? (body as { error: string }).error\n : null) || `HTTP ${res.status}`;\n throw new HornerosError(message, res.status, body);\n }\n\n if (res.status === 204) {\n return undefined as T;\n }\n\n return res.json() as Promise<T>;\n }\n}\n","import type { ConnectionData } from \"./types\";\n\nexport class AuthScheme {\n static APIKey(params: { api_key: string; [k: string]: string }): ConnectionData {\n return { type: \"api_key\", data: params };\n }\n\n static Bearer(params: { token: string }): ConnectionData {\n return { type: \"bearer\", data: params };\n }\n\n static Basic(params: { username: string; password: string }): ConnectionData {\n return { type: \"basic\", data: params };\n }\n\n static OAuth2(params: {\n access_token: string;\n refresh_token?: string;\n }): ConnectionData {\n return {\n type: \"oauth2\",\n data: params as Record<string, string>,\n };\n }\n\n static GoogleLogin(): ConnectionData {\n return { type: \"google_login\", data: {} };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/mcps.ts","../src/connections.ts","../src/tools.ts","../src/client.ts","../src/auth-scheme.ts"],"sourcesContent":["export { HornerosSSP } from \"./client\";\nexport { AuthScheme } from \"./auth-scheme\";\nexport { Mcps } from \"./mcps\";\nexport { Connections, ConnectionRequest } from \"./connections\";\nexport { Tools } from \"./tools\";\n\n// Errors\nexport {\n HornerosError,\n NotFoundError,\n ValidationError,\n ConnectionTimeoutError,\n HORNEROS_SDK_ERROR_CODES,\n} from \"./errors\";\n\n// Types\nexport type {\n HornerosSSPConfig,\n McpInfo,\n McpDetail,\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ConnectionData,\n ApiResponse,\n ApiError,\n} from \"./types\";\n","// ── Error codes ─────────────────────────────────────────────\n\nexport const HORNEROS_SDK_ERROR_CODES = {\n BACKEND: {\n NOT_FOUND: \"BACKEND::NOT_FOUND\",\n RATE_LIMIT: \"BACKEND::RATE_LIMIT\",\n BAD_REQUEST: \"BACKEND::BAD_REQUEST\",\n UNAUTHORIZED: \"BACKEND::UNAUTHORIZED\",\n SERVER_ERROR: \"BACKEND::SERVER_ERROR\",\n SERVER_UNAVAILABLE: \"BACKEND::SERVER_UNAVAILABLE\",\n UNKNOWN: \"BACKEND::UNKNOWN\",\n },\n COMMON: {\n API_KEY_UNAVAILABLE: \"COMMON::API_KEY_UNAVAILABLE\",\n BASE_URL_NOT_REACHABLE: \"COMMON::BASE_URL_NOT_REACHABLE\",\n UNKNOWN: \"COMMON::UNKNOWN\",\n INVALID_PARAMS: \"COMMON::INVALID_PARAMS\",\n },\n SDK: {\n NO_CONNECTED_ACCOUNT: \"SDK::NO_CONNECTED_ACCOUNT\",\n CONNECTION_TIMEOUT: \"SDK::CONNECTION_TIMEOUT\",\n INVALID_PARAMETER: \"SDK::INVALID_PARAMETER\",\n },\n} as const;\n\n// ── Base error ──────────────────────────────────────────────\n\nlet errorCounter = 0;\n\nexport class HornerosError extends Error {\n public readonly errCode: string;\n public readonly statusCode: number;\n public readonly body: unknown;\n public readonly description?: string;\n public readonly possibleFix?: string;\n public readonly errorId: string;\n public readonly timestamp: string;\n\n constructor(\n errCode: string,\n message: string,\n statusCode: number,\n body?: unknown,\n description?: string,\n possibleFix?: string\n ) {\n super(message);\n this.name = \"HornerosError\";\n this.errCode = errCode;\n this.statusCode = statusCode;\n this.body = body;\n this.description = description;\n this.possibleFix = possibleFix;\n this.errorId = `horneros_${Date.now()}_${++errorCounter}`;\n this.timestamp = new Date().toISOString();\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n errCode: this.errCode,\n message: this.message,\n statusCode: this.statusCode,\n description: this.description,\n possibleFix: this.possibleFix,\n errorId: this.errorId,\n timestamp: this.timestamp,\n body: this.body,\n };\n }\n}\n\n// ── Specialized errors ──────────────────────────────────────\n\nexport class NotFoundError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND, message, 404, body);\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST, message, 400, body);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ConnectionTimeoutError extends HornerosError {\n constructor(message = \"Connection timed out waiting for activation\") {\n super(\n HORNEROS_SDK_ERROR_CODES.SDK.CONNECTION_TIMEOUT,\n message,\n 408,\n undefined,\n \"The connection did not become active within the timeout period.\",\n \"Increase the timeout value or check that the user completed the authentication flow.\"\n );\n this.name = \"ConnectionTimeoutError\";\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type { McpInfo, McpDetail, ApiResponse } from \"./types\";\n\nexport class Mcps {\n constructor(private client: HornerosSSP) {}\n\n async list(): Promise<McpInfo[]> {\n const res = await this.client.fetch<ApiResponse<McpInfo[]>>(\"/mcps\");\n return res.data;\n }\n\n async get(slug: string): Promise<McpDetail> {\n const res = await this.client.fetch<ApiResponse<McpDetail>>(\n `/mcps/${encodeURIComponent(slug)}`\n );\n return res.data;\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ApiResponse,\n} from \"./types\";\nimport { ConnectionTimeoutError } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpUrl: string | null;\n public readonly token: string | null;\n public readonly redirectUrl: string | null;\n public readonly status: \"active\" | \"pending\";\n\n constructor(\n private client: HornerosSSP,\n data: ConnectionRequestData\n ) {\n this.id = data.id;\n this.mcpUrl = data.mcpUrl;\n this.token = data.token;\n this.redirectUrl = data.redirectUrl;\n this.status = data.status;\n }\n\n /**\n * Polls the connection until it becomes active.\n * Useful for OAuth/interactive flows where the user needs to\n * complete authentication in a browser.\n * @param timeout Max wait time in ms (default: 120000 = 2 min)\n */\n async waitForConnection(timeout = 120_000): Promise<ConnectionInfo> {\n if (this.status === \"active\") {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n return res.data;\n }\n\n const start = Date.now();\n const interval = 2000;\n\n while (Date.now() - start < timeout) {\n await sleep(interval);\n try {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n if (res.data.status === \"active\") {\n return res.data;\n }\n } catch {\n // Connection not yet created, keep polling\n }\n }\n\n throw new ConnectionTimeoutError();\n }\n}\n\nexport class Connections {\n constructor(private client: HornerosSSP) {}\n\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n };\n\n if (params.appName) body.app_name = params.appName;\n if (params.userId) body.user_id = params.userId;\n if (params.credentials) body.credentials = params.credentials;\n if (params.authScheme) body.auth_scheme = params.authScheme;\n\n const res = await this.client.fetch<ApiResponse<ConnectionRequestData>>(\n \"/connections\",\n { method: \"POST\", body: JSON.stringify(body) }\n );\n\n return new ConnectionRequest(this.client, res.data);\n }\n\n async list(): Promise<ConnectionInfo[]> {\n const res =\n await this.client.fetch<ApiResponse<ConnectionInfo[]>>(\"/connections\");\n return res.data;\n }\n\n async get(id: string): Promise<ConnectionInfo> {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(id)}`\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.fetch<void>(\n `/connections/${encodeURIComponent(id)}`,\n { method: \"DELETE\" }\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ApiResponse,\n} from \"./types\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n async list(mcpSlug: string): Promise<ToolDefinition[]> {\n const res = await this.client.fetch<ApiResponse<ToolDefinition[]>>(\n `/mcps/${encodeURIComponent(mcpSlug)}/tools`\n );\n return res.data;\n }\n\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify({\n mcp_slug: params.mcpSlug,\n connection_id: params.connectionId,\n tool_name: params.toolName,\n arguments: params.arguments,\n }),\n }\n );\n return res.data;\n }\n}\n","import type { HornerosSSPConfig } from \"./types\";\nimport { HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\nimport { Mcps } from \"./mcps\";\nimport { Connections } from \"./connections\";\nimport { Tools } from \"./tools\";\n\n// ── Helpers ─────────────────────────────────────────────────\n\nfunction getEnvVariable(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n\nconst DEFAULT_BASE_URL = \"http://localhost:3000\";\n\nfunction resolveConfig(config?: HornerosSSPConfig) {\n const baseUrl =\n config?.baseUrl ||\n getEnvVariable(\"HORNEROS_BASE_URL\") ||\n DEFAULT_BASE_URL;\n\n const apiKey =\n config?.apiKey ||\n getEnvVariable(\"HORNEROS_API_KEY\") ||\n \"\";\n\n const runtime = config?.runtime || getEnvVariable(\"HORNEROS_RUNTIME\") || \"\";\n\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), apiKey, runtime };\n}\n\n// ── Main client ─────────────────────────────────────────────\n\nexport class HornerosSSP {\n public readonly mcps: Mcps;\n public readonly connections: Connections;\n public readonly tools: Tools;\n\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly runtime: string;\n\n constructor(config?: HornerosSSPConfig) {\n const resolved = resolveConfig(config);\n\n if (!resolved.apiKey) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.API_KEY_UNAVAILABLE,\n \"🔑 API Key is not provided\",\n 401,\n undefined,\n \"You need to provide an API key in the constructor or as the environment variable HORNEROS_API_KEY.\",\n 'Provide a valid API key: new HornerosSSP({ apiKey: \"hsp_xxx\" }) or set HORNEROS_API_KEY in your environment.'\n );\n }\n\n this.baseUrl = resolved.baseUrl;\n this.apiKey = resolved.apiKey;\n this.runtime = resolved.runtime;\n\n this.mcps = new Mcps(this);\n this.connections = new Connections(this);\n this.tools = new Tools(this);\n }\n\n /** @internal */\n async fetch<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}/api/v1${path}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Source\": \"js_sdk\",\n \"X-Runtime\": this.runtime,\n ...(options.headers as Record<string, string>),\n };\n\n const res = await globalThis.fetch(url, {\n ...options,\n headers,\n });\n\n if (!res.ok) {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = await res.text().catch(() => null);\n }\n\n const message =\n (body && typeof body === \"object\" && \"error\" in body\n ? (body as { error: string }).error\n : null) || `HTTP ${res.status}`;\n\n const errCode =\n res.status === 404\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND\n : res.status === 401\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.UNAUTHORIZED\n : res.status === 429\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.RATE_LIMIT\n : res.status === 400\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST\n : res.status >= 500\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.SERVER_ERROR\n : HORNEROS_SDK_ERROR_CODES.BACKEND.UNKNOWN;\n\n throw new HornerosError(errCode, message, res.status, body);\n }\n\n if (res.status === 204) {\n return undefined as T;\n }\n\n return res.json() as Promise<T>;\n }\n}\n","import type { ConnectionData } from \"./types\";\n\nexport class AuthScheme {\n static APIKey(params: { api_key: string; [k: string]: string }): ConnectionData {\n return { type: \"api_key\", data: params };\n }\n\n static Bearer(params: { token: string }): ConnectionData {\n return { type: \"bearer\", data: params };\n }\n\n static Basic(params: { username: string; password: string }): ConnectionData {\n return { type: \"basic\", data: params };\n }\n\n static OAuth2(params: {\n access_token: string;\n refresh_token?: string;\n }): ConnectionData {\n return {\n type: \"oauth2\",\n data: params as Record<string, string>,\n };\n }\n\n static GoogleLogin(): ConnectionData {\n return { type: \"google_login\", data: {} };\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -1,27 +1,75 @@
1
1
  // src/errors.ts
2
+ var HORNEROS_SDK_ERROR_CODES = {
3
+ BACKEND: {
4
+ NOT_FOUND: "BACKEND::NOT_FOUND",
5
+ RATE_LIMIT: "BACKEND::RATE_LIMIT",
6
+ BAD_REQUEST: "BACKEND::BAD_REQUEST",
7
+ UNAUTHORIZED: "BACKEND::UNAUTHORIZED",
8
+ SERVER_ERROR: "BACKEND::SERVER_ERROR",
9
+ SERVER_UNAVAILABLE: "BACKEND::SERVER_UNAVAILABLE",
10
+ UNKNOWN: "BACKEND::UNKNOWN"
11
+ },
12
+ COMMON: {
13
+ API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE",
14
+ BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE",
15
+ UNKNOWN: "COMMON::UNKNOWN",
16
+ INVALID_PARAMS: "COMMON::INVALID_PARAMS"
17
+ },
18
+ SDK: {
19
+ NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT",
20
+ CONNECTION_TIMEOUT: "SDK::CONNECTION_TIMEOUT",
21
+ INVALID_PARAMETER: "SDK::INVALID_PARAMETER"
22
+ }
23
+ };
24
+ var errorCounter = 0;
2
25
  var HornerosError = class extends Error {
3
- constructor(message, statusCode, body) {
26
+ constructor(errCode, message, statusCode, body, description, possibleFix) {
4
27
  super(message);
5
28
  this.name = "HornerosError";
29
+ this.errCode = errCode;
6
30
  this.statusCode = statusCode;
7
31
  this.body = body;
32
+ this.description = description;
33
+ this.possibleFix = possibleFix;
34
+ this.errorId = `horneros_${Date.now()}_${++errorCounter}`;
35
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
36
+ }
37
+ toJSON() {
38
+ return {
39
+ name: this.name,
40
+ errCode: this.errCode,
41
+ message: this.message,
42
+ statusCode: this.statusCode,
43
+ description: this.description,
44
+ possibleFix: this.possibleFix,
45
+ errorId: this.errorId,
46
+ timestamp: this.timestamp,
47
+ body: this.body
48
+ };
8
49
  }
9
50
  };
10
51
  var NotFoundError = class extends HornerosError {
11
52
  constructor(message, body) {
12
- super(message, 404, body);
53
+ super(HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND, message, 404, body);
13
54
  this.name = "NotFoundError";
14
55
  }
15
56
  };
16
57
  var ValidationError = class extends HornerosError {
17
58
  constructor(message, body) {
18
- super(message, 400, body);
59
+ super(HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST, message, 400, body);
19
60
  this.name = "ValidationError";
20
61
  }
21
62
  };
22
63
  var ConnectionTimeoutError = class extends HornerosError {
23
64
  constructor(message = "Connection timed out waiting for activation") {
24
- super(message, 408);
65
+ super(
66
+ HORNEROS_SDK_ERROR_CODES.SDK.CONNECTION_TIMEOUT,
67
+ message,
68
+ 408,
69
+ void 0,
70
+ "The connection did not become active within the timeout period.",
71
+ "Increase the timeout value or check that the user completed the authentication flow."
72
+ );
25
73
  this.name = "ConnectionTimeoutError";
26
74
  }
27
75
  };
@@ -151,9 +199,35 @@ var Tools = class {
151
199
  };
152
200
 
153
201
  // src/client.ts
202
+ function getEnvVariable(name) {
203
+ if (typeof process !== "undefined" && process.env) {
204
+ return process.env[name];
205
+ }
206
+ return void 0;
207
+ }
208
+ var DEFAULT_BASE_URL = "http://localhost:3000";
209
+ function resolveConfig(config) {
210
+ const baseUrl = config?.baseUrl || getEnvVariable("HORNEROS_BASE_URL") || DEFAULT_BASE_URL;
211
+ const apiKey = config?.apiKey || getEnvVariable("HORNEROS_API_KEY") || "";
212
+ const runtime = config?.runtime || getEnvVariable("HORNEROS_RUNTIME") || "";
213
+ return { baseUrl: baseUrl.replace(/\/+$/, ""), apiKey, runtime };
214
+ }
154
215
  var HornerosSSP = class {
155
216
  constructor(config) {
156
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
217
+ const resolved = resolveConfig(config);
218
+ if (!resolved.apiKey) {
219
+ throw new HornerosError(
220
+ HORNEROS_SDK_ERROR_CODES.COMMON.API_KEY_UNAVAILABLE,
221
+ "\u{1F511} API Key is not provided",
222
+ 401,
223
+ void 0,
224
+ "You need to provide an API key in the constructor or as the environment variable HORNEROS_API_KEY.",
225
+ 'Provide a valid API key: new HornerosSSP({ apiKey: "hsp_xxx" }) or set HORNEROS_API_KEY in your environment.'
226
+ );
227
+ }
228
+ this.baseUrl = resolved.baseUrl;
229
+ this.apiKey = resolved.apiKey;
230
+ this.runtime = resolved.runtime;
157
231
  this.mcps = new Mcps(this);
158
232
  this.connections = new Connections(this);
159
233
  this.tools = new Tools(this);
@@ -163,6 +237,9 @@ var HornerosSSP = class {
163
237
  const url = `${this.baseUrl}/api/v1${path}`;
164
238
  const headers = {
165
239
  "Content-Type": "application/json",
240
+ "X-Api-Key": this.apiKey,
241
+ "X-Source": "js_sdk",
242
+ "X-Runtime": this.runtime,
166
243
  ...options.headers
167
244
  };
168
245
  const res = await globalThis.fetch(url, {
@@ -177,7 +254,8 @@ var HornerosSSP = class {
177
254
  body = await res.text().catch(() => null);
178
255
  }
179
256
  const message = (body && typeof body === "object" && "error" in body ? body.error : null) || `HTTP ${res.status}`;
180
- throw new HornerosError(message, res.status, body);
257
+ const errCode = res.status === 404 ? HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND : res.status === 401 ? HORNEROS_SDK_ERROR_CODES.BACKEND.UNAUTHORIZED : res.status === 429 ? HORNEROS_SDK_ERROR_CODES.BACKEND.RATE_LIMIT : res.status === 400 ? HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST : res.status >= 500 ? HORNEROS_SDK_ERROR_CODES.BACKEND.SERVER_ERROR : HORNEROS_SDK_ERROR_CODES.BACKEND.UNKNOWN;
258
+ throw new HornerosError(errCode, message, res.status, body);
181
259
  }
182
260
  if (res.status === 204) {
183
261
  return void 0;
@@ -212,6 +290,7 @@ export {
212
290
  ConnectionRequest,
213
291
  ConnectionTimeoutError,
214
292
  Connections,
293
+ HORNEROS_SDK_ERROR_CODES,
215
294
  HornerosError,
216
295
  HornerosSSP,
217
296
  Mcps,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/mcps.ts","../src/connections.ts","../src/tools.ts","../src/client.ts","../src/auth-scheme.ts"],"sourcesContent":["export class HornerosError extends Error {\n public readonly statusCode: number;\n public readonly body: unknown;\n\n constructor(message: string, statusCode: number, body?: unknown) {\n super(message);\n this.name = \"HornerosError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n\nexport class NotFoundError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(message, 404, body);\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(message, 400, body);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ConnectionTimeoutError extends HornerosError {\n constructor(message = \"Connection timed out waiting for activation\") {\n super(message, 408);\n this.name = \"ConnectionTimeoutError\";\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type { McpInfo, McpDetail, ApiResponse } from \"./types\";\n\nexport class Mcps {\n constructor(private client: HornerosSSP) {}\n\n async list(): Promise<McpInfo[]> {\n const res = await this.client.fetch<ApiResponse<McpInfo[]>>(\"/mcps\");\n return res.data;\n }\n\n async get(slug: string): Promise<McpDetail> {\n const res = await this.client.fetch<ApiResponse<McpDetail>>(\n `/mcps/${encodeURIComponent(slug)}`\n );\n return res.data;\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ApiResponse,\n} from \"./types\";\nimport { ConnectionTimeoutError } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpUrl: string | null;\n public readonly token: string | null;\n public readonly redirectUrl: string | null;\n public readonly status: \"active\" | \"pending\";\n\n constructor(\n private client: HornerosSSP,\n data: ConnectionRequestData\n ) {\n this.id = data.id;\n this.mcpUrl = data.mcpUrl;\n this.token = data.token;\n this.redirectUrl = data.redirectUrl;\n this.status = data.status;\n }\n\n /**\n * Polls the connection until it becomes active.\n * Useful for OAuth/interactive flows where the user needs to\n * complete authentication in a browser.\n * @param timeout Max wait time in ms (default: 120000 = 2 min)\n */\n async waitForConnection(timeout = 120_000): Promise<ConnectionInfo> {\n if (this.status === \"active\") {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n return res.data;\n }\n\n const start = Date.now();\n const interval = 2000;\n\n while (Date.now() - start < timeout) {\n await sleep(interval);\n try {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n if (res.data.status === \"active\") {\n return res.data;\n }\n } catch {\n // Connection not yet created, keep polling\n }\n }\n\n throw new ConnectionTimeoutError();\n }\n}\n\nexport class Connections {\n constructor(private client: HornerosSSP) {}\n\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n };\n\n if (params.appName) body.app_name = params.appName;\n if (params.userId) body.user_id = params.userId;\n if (params.credentials) body.credentials = params.credentials;\n if (params.authScheme) body.auth_scheme = params.authScheme;\n\n const res = await this.client.fetch<ApiResponse<ConnectionRequestData>>(\n \"/connections\",\n { method: \"POST\", body: JSON.stringify(body) }\n );\n\n return new ConnectionRequest(this.client, res.data);\n }\n\n async list(): Promise<ConnectionInfo[]> {\n const res =\n await this.client.fetch<ApiResponse<ConnectionInfo[]>>(\"/connections\");\n return res.data;\n }\n\n async get(id: string): Promise<ConnectionInfo> {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(id)}`\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.fetch<void>(\n `/connections/${encodeURIComponent(id)}`,\n { method: \"DELETE\" }\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ApiResponse,\n} from \"./types\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n async list(mcpSlug: string): Promise<ToolDefinition[]> {\n const res = await this.client.fetch<ApiResponse<ToolDefinition[]>>(\n `/mcps/${encodeURIComponent(mcpSlug)}/tools`\n );\n return res.data;\n }\n\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify({\n mcp_slug: params.mcpSlug,\n connection_id: params.connectionId,\n tool_name: params.toolName,\n arguments: params.arguments,\n }),\n }\n );\n return res.data;\n }\n}\n","import type { HornerosSSPConfig } from \"./types\";\nimport { HornerosError } from \"./errors\";\nimport { Mcps } from \"./mcps\";\nimport { Connections } from \"./connections\";\nimport { Tools } from \"./tools\";\n\nexport class HornerosSSP {\n public readonly mcps: Mcps;\n public readonly connections: Connections;\n public readonly tools: Tools;\n\n private readonly baseUrl: string;\n\n constructor(config: HornerosSSPConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/+$/, \"\");\n\n this.mcps = new Mcps(this);\n this.connections = new Connections(this);\n this.tools = new Tools(this);\n }\n\n /** @internal */\n async fetch<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}/api/v1${path}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n\n const res = await globalThis.fetch(url, {\n ...options,\n headers,\n });\n\n if (!res.ok) {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = await res.text().catch(() => null);\n }\n const message =\n (body && typeof body === \"object\" && \"error\" in body\n ? (body as { error: string }).error\n : null) || `HTTP ${res.status}`;\n throw new HornerosError(message, res.status, body);\n }\n\n if (res.status === 204) {\n return undefined as T;\n }\n\n return res.json() as Promise<T>;\n }\n}\n","import type { ConnectionData } from \"./types\";\n\nexport class AuthScheme {\n static APIKey(params: { api_key: string; [k: string]: string }): ConnectionData {\n return { type: \"api_key\", data: params };\n }\n\n static Bearer(params: { token: string }): ConnectionData {\n return { type: \"bearer\", data: params };\n }\n\n static Basic(params: { username: string; password: string }): ConnectionData {\n return { type: \"basic\", data: params };\n }\n\n static OAuth2(params: {\n access_token: string;\n refresh_token?: string;\n }): ConnectionData {\n return {\n type: \"oauth2\",\n data: params as Record<string, string>,\n };\n }\n\n static GoogleLogin(): ConnectionData {\n return { type: \"google_login\", data: {} };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/mcps.ts","../src/connections.ts","../src/tools.ts","../src/client.ts","../src/auth-scheme.ts"],"sourcesContent":["// ── Error codes ─────────────────────────────────────────────\n\nexport const HORNEROS_SDK_ERROR_CODES = {\n BACKEND: {\n NOT_FOUND: \"BACKEND::NOT_FOUND\",\n RATE_LIMIT: \"BACKEND::RATE_LIMIT\",\n BAD_REQUEST: \"BACKEND::BAD_REQUEST\",\n UNAUTHORIZED: \"BACKEND::UNAUTHORIZED\",\n SERVER_ERROR: \"BACKEND::SERVER_ERROR\",\n SERVER_UNAVAILABLE: \"BACKEND::SERVER_UNAVAILABLE\",\n UNKNOWN: \"BACKEND::UNKNOWN\",\n },\n COMMON: {\n API_KEY_UNAVAILABLE: \"COMMON::API_KEY_UNAVAILABLE\",\n BASE_URL_NOT_REACHABLE: \"COMMON::BASE_URL_NOT_REACHABLE\",\n UNKNOWN: \"COMMON::UNKNOWN\",\n INVALID_PARAMS: \"COMMON::INVALID_PARAMS\",\n },\n SDK: {\n NO_CONNECTED_ACCOUNT: \"SDK::NO_CONNECTED_ACCOUNT\",\n CONNECTION_TIMEOUT: \"SDK::CONNECTION_TIMEOUT\",\n INVALID_PARAMETER: \"SDK::INVALID_PARAMETER\",\n },\n} as const;\n\n// ── Base error ──────────────────────────────────────────────\n\nlet errorCounter = 0;\n\nexport class HornerosError extends Error {\n public readonly errCode: string;\n public readonly statusCode: number;\n public readonly body: unknown;\n public readonly description?: string;\n public readonly possibleFix?: string;\n public readonly errorId: string;\n public readonly timestamp: string;\n\n constructor(\n errCode: string,\n message: string,\n statusCode: number,\n body?: unknown,\n description?: string,\n possibleFix?: string\n ) {\n super(message);\n this.name = \"HornerosError\";\n this.errCode = errCode;\n this.statusCode = statusCode;\n this.body = body;\n this.description = description;\n this.possibleFix = possibleFix;\n this.errorId = `horneros_${Date.now()}_${++errorCounter}`;\n this.timestamp = new Date().toISOString();\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n errCode: this.errCode,\n message: this.message,\n statusCode: this.statusCode,\n description: this.description,\n possibleFix: this.possibleFix,\n errorId: this.errorId,\n timestamp: this.timestamp,\n body: this.body,\n };\n }\n}\n\n// ── Specialized errors ──────────────────────────────────────\n\nexport class NotFoundError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND, message, 404, body);\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends HornerosError {\n constructor(message: string, body?: unknown) {\n super(HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST, message, 400, body);\n this.name = \"ValidationError\";\n }\n}\n\nexport class ConnectionTimeoutError extends HornerosError {\n constructor(message = \"Connection timed out waiting for activation\") {\n super(\n HORNEROS_SDK_ERROR_CODES.SDK.CONNECTION_TIMEOUT,\n message,\n 408,\n undefined,\n \"The connection did not become active within the timeout period.\",\n \"Increase the timeout value or check that the user completed the authentication flow.\"\n );\n this.name = \"ConnectionTimeoutError\";\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type { McpInfo, McpDetail, ApiResponse } from \"./types\";\n\nexport class Mcps {\n constructor(private client: HornerosSSP) {}\n\n async list(): Promise<McpInfo[]> {\n const res = await this.client.fetch<ApiResponse<McpInfo[]>>(\"/mcps\");\n return res.data;\n }\n\n async get(slug: string): Promise<McpDetail> {\n const res = await this.client.fetch<ApiResponse<McpDetail>>(\n `/mcps/${encodeURIComponent(slug)}`\n );\n return res.data;\n }\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ConnectionInfo,\n ConnectionRequestData,\n InitiateConnectionParams,\n ApiResponse,\n} from \"./types\";\nimport { ConnectionTimeoutError } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpUrl: string | null;\n public readonly token: string | null;\n public readonly redirectUrl: string | null;\n public readonly status: \"active\" | \"pending\";\n\n constructor(\n private client: HornerosSSP,\n data: ConnectionRequestData\n ) {\n this.id = data.id;\n this.mcpUrl = data.mcpUrl;\n this.token = data.token;\n this.redirectUrl = data.redirectUrl;\n this.status = data.status;\n }\n\n /**\n * Polls the connection until it becomes active.\n * Useful for OAuth/interactive flows where the user needs to\n * complete authentication in a browser.\n * @param timeout Max wait time in ms (default: 120000 = 2 min)\n */\n async waitForConnection(timeout = 120_000): Promise<ConnectionInfo> {\n if (this.status === \"active\") {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n return res.data;\n }\n\n const start = Date.now();\n const interval = 2000;\n\n while (Date.now() - start < timeout) {\n await sleep(interval);\n try {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(this.id)}`\n );\n if (res.data.status === \"active\") {\n return res.data;\n }\n } catch {\n // Connection not yet created, keep polling\n }\n }\n\n throw new ConnectionTimeoutError();\n }\n}\n\nexport class Connections {\n constructor(private client: HornerosSSP) {}\n\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n };\n\n if (params.appName) body.app_name = params.appName;\n if (params.userId) body.user_id = params.userId;\n if (params.credentials) body.credentials = params.credentials;\n if (params.authScheme) body.auth_scheme = params.authScheme;\n\n const res = await this.client.fetch<ApiResponse<ConnectionRequestData>>(\n \"/connections\",\n { method: \"POST\", body: JSON.stringify(body) }\n );\n\n return new ConnectionRequest(this.client, res.data);\n }\n\n async list(): Promise<ConnectionInfo[]> {\n const res =\n await this.client.fetch<ApiResponse<ConnectionInfo[]>>(\"/connections\");\n return res.data;\n }\n\n async get(id: string): Promise<ConnectionInfo> {\n const res = await this.client.fetch<ApiResponse<ConnectionInfo>>(\n `/connections/${encodeURIComponent(id)}`\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.fetch<void>(\n `/connections/${encodeURIComponent(id)}`,\n { method: \"DELETE\" }\n );\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HornerosSSP } from \"./client\";\nimport type {\n ToolDefinition,\n ToolResult,\n ExecuteToolParams,\n ApiResponse,\n} from \"./types\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n async list(mcpSlug: string): Promise<ToolDefinition[]> {\n const res = await this.client.fetch<ApiResponse<ToolDefinition[]>>(\n `/mcps/${encodeURIComponent(mcpSlug)}/tools`\n );\n return res.data;\n }\n\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify({\n mcp_slug: params.mcpSlug,\n connection_id: params.connectionId,\n tool_name: params.toolName,\n arguments: params.arguments,\n }),\n }\n );\n return res.data;\n }\n}\n","import type { HornerosSSPConfig } from \"./types\";\nimport { HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\nimport { Mcps } from \"./mcps\";\nimport { Connections } from \"./connections\";\nimport { Tools } from \"./tools\";\n\n// ── Helpers ─────────────────────────────────────────────────\n\nfunction getEnvVariable(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n\nconst DEFAULT_BASE_URL = \"http://localhost:3000\";\n\nfunction resolveConfig(config?: HornerosSSPConfig) {\n const baseUrl =\n config?.baseUrl ||\n getEnvVariable(\"HORNEROS_BASE_URL\") ||\n DEFAULT_BASE_URL;\n\n const apiKey =\n config?.apiKey ||\n getEnvVariable(\"HORNEROS_API_KEY\") ||\n \"\";\n\n const runtime = config?.runtime || getEnvVariable(\"HORNEROS_RUNTIME\") || \"\";\n\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), apiKey, runtime };\n}\n\n// ── Main client ─────────────────────────────────────────────\n\nexport class HornerosSSP {\n public readonly mcps: Mcps;\n public readonly connections: Connections;\n public readonly tools: Tools;\n\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly runtime: string;\n\n constructor(config?: HornerosSSPConfig) {\n const resolved = resolveConfig(config);\n\n if (!resolved.apiKey) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.API_KEY_UNAVAILABLE,\n \"🔑 API Key is not provided\",\n 401,\n undefined,\n \"You need to provide an API key in the constructor or as the environment variable HORNEROS_API_KEY.\",\n 'Provide a valid API key: new HornerosSSP({ apiKey: \"hsp_xxx\" }) or set HORNEROS_API_KEY in your environment.'\n );\n }\n\n this.baseUrl = resolved.baseUrl;\n this.apiKey = resolved.apiKey;\n this.runtime = resolved.runtime;\n\n this.mcps = new Mcps(this);\n this.connections = new Connections(this);\n this.tools = new Tools(this);\n }\n\n /** @internal */\n async fetch<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}/api/v1${path}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n \"X-Source\": \"js_sdk\",\n \"X-Runtime\": this.runtime,\n ...(options.headers as Record<string, string>),\n };\n\n const res = await globalThis.fetch(url, {\n ...options,\n headers,\n });\n\n if (!res.ok) {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = await res.text().catch(() => null);\n }\n\n const message =\n (body && typeof body === \"object\" && \"error\" in body\n ? (body as { error: string }).error\n : null) || `HTTP ${res.status}`;\n\n const errCode =\n res.status === 404\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.NOT_FOUND\n : res.status === 401\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.UNAUTHORIZED\n : res.status === 429\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.RATE_LIMIT\n : res.status === 400\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.BAD_REQUEST\n : res.status >= 500\n ? HORNEROS_SDK_ERROR_CODES.BACKEND.SERVER_ERROR\n : HORNEROS_SDK_ERROR_CODES.BACKEND.UNKNOWN;\n\n throw new HornerosError(errCode, message, res.status, body);\n }\n\n if (res.status === 204) {\n return undefined as T;\n }\n\n return res.json() as Promise<T>;\n }\n}\n","import type { ConnectionData } from \"./types\";\n\nexport class AuthScheme {\n static APIKey(params: { api_key: string; [k: string]: string }): ConnectionData {\n return { type: \"api_key\", data: params };\n }\n\n static Bearer(params: { token: string }): ConnectionData {\n return { type: \"bearer\", data: params };\n }\n\n static Basic(params: { username: string; password: string }): ConnectionData {\n return { type: \"basic\", data: params };\n }\n\n static OAuth2(params: {\n access_token: string;\n refresh_token?: string;\n }): ConnectionData {\n return {\n type: \"oauth2\",\n data: params as Record<string, string>,\n };\n }\n\n static GoogleLogin(): ConnectionData {\n return { type: \"google_login\", data: {} };\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hornerosssp",
3
- "version": "0.1.0",
4
- "description": "SDK for HornerosSSP - integrate MCPs into any app",
3
+ "version": "0.3.0",
4
+ "description": "SDK and CLI for HornerosSSP - integrate MCPs into any app",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
@@ -12,6 +12,9 @@
12
12
  "require": "./dist/index.js"
13
13
  }
14
14
  },
15
+ "bin": {
16
+ "hornerosssp": "./dist/cli/index.js"
17
+ },
15
18
  "files": [
16
19
  "dist"
17
20
  ],
@@ -19,7 +22,15 @@
19
22
  "build": "tsup",
20
23
  "dev": "tsup --watch"
21
24
  },
25
+ "dependencies": {
26
+ "chalk": "^4.1.2",
27
+ "commander": "^12.1.0",
28
+ "inquirer": "^10.2.2",
29
+ "open": "^8.4.0"
30
+ },
22
31
  "devDependencies": {
32
+ "@types/inquirer": "^9.0.7",
33
+ "composio-core": "^0.5.39",
23
34
  "tsup": "^8.0.0",
24
35
  "typescript": "^5.0.0"
25
36
  },