hornerosssp 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # HornerosSSP SDK
2
+
3
+ SDK oficial para integrar HornerosSSP en tu aplicacion. Permite conectar usuarios de tu app a integraciones como Kommo CRM, Chatwoot, NotebookLM, MercadoPago, TiendaNube, Correo Argentino y ARCA.
4
+
5
+ ## Instalacion
6
+
7
+ ```bash
8
+ npm install hornerosssp
9
+ ```
10
+
11
+ ## Inicio Rapido
12
+
13
+ ```typescript
14
+ import { HornerosSSP } from "hornerosssp";
15
+
16
+ // Inicializar cliente con tu API key
17
+ const client = new HornerosSSP({
18
+ apiKey: "hsp_tu_api_key_aqui"
19
+ });
20
+
21
+ // Listar integraciones disponibles
22
+ const mcps = await client.mcps.list();
23
+ // [{ slug: "kommo-mcp", name: "Kommo CRM", ... }, ...]
24
+
25
+ // Crear conexion para un usuario de tu app
26
+ const conn = await client.connections.initiate({
27
+ mcpSlug: "kommo-mcp",
28
+ entityId: "user_123", // ID del usuario en TU app
29
+ credentials: {
30
+ access_token: "token_del_usuario",
31
+ base_domain: "empresa.kommo.com"
32
+ }
33
+ });
34
+
35
+ // Ejecutar herramienta
36
+ const result = await client.tools.execute({
37
+ mcpSlug: "kommo-mcp",
38
+ entityId: "user_123",
39
+ toolName: "get_leads",
40
+ arguments: { limit: 10 }
41
+ });
42
+ ```
43
+
44
+ ## Conceptos Clave
45
+
46
+ ### API Key
47
+ Tu API key (`hsp_xxx`) identifica a tu aplicacion. Obtenla desde el dashboard de HornerosSSP.
48
+
49
+ ### Entity ID
50
+ El `entityId` es el identificador del usuario final en TU aplicacion. Cada usuario puede tener sus propias conexiones a diferentes integraciones.
51
+
52
+ ### Conexiones
53
+ Una conexion almacena las credenciales de un usuario para una integracion especifica. Por ejemplo, si el usuario "user_123" conecta su cuenta de Kommo, las credenciales se guardan asociadas a ese entity.
54
+
55
+ ## API Reference
56
+
57
+ ### Listar MCPs Disponibles
58
+
59
+ ```typescript
60
+ const mcps = await client.mcps.list();
61
+ ```
62
+
63
+ Retorna todas las integraciones disponibles. No requiere configuracion previa.
64
+
65
+ **Respuesta:**
66
+ ```typescript
67
+ [
68
+ {
69
+ slug: "kommo-mcp",
70
+ name: "Kommo CRM",
71
+ description: "Gestiona leads, contactos y mensajes...",
72
+ requiredCredentials: ["access_token", "base_domain"],
73
+ toolCount: 11,
74
+ category: "CRM"
75
+ },
76
+ // ...
77
+ ]
78
+ ```
79
+
80
+ ### Obtener Detalle de un MCP
81
+
82
+ ```typescript
83
+ const mcp = await client.mcps.get("kommo-mcp");
84
+ ```
85
+
86
+ **Respuesta:**
87
+ ```typescript
88
+ {
89
+ slug: "kommo-mcp",
90
+ name: "Kommo CRM",
91
+ description: "...",
92
+ requiredCredentials: ["access_token", "base_domain"],
93
+ tools: [
94
+ { name: "get_leads", description: "Obtiene lista de leads" },
95
+ // ...
96
+ ]
97
+ }
98
+ ```
99
+
100
+ ### Crear Conexion
101
+
102
+ ```typescript
103
+ const conn = await client.connections.initiate({
104
+ mcpSlug: "kommo-mcp", // Requerido: slug del MCP
105
+ entityId: "user_123", // Requerido: ID del usuario en tu app
106
+ credentials: { // Requerido: credenciales del usuario
107
+ access_token: "xxx",
108
+ base_domain: "empresa.kommo.com"
109
+ },
110
+ appName: "Mi App" // Opcional: nombre descriptivo
111
+ });
112
+ ```
113
+
114
+ **Respuesta:**
115
+ ```typescript
116
+ {
117
+ id: "conn_abc123",
118
+ mcpSlug: "kommo-mcp",
119
+ entityId: "user_123",
120
+ mcpUrl: "https://hornerosssp.com/api/mcp/kommo-mcp/conn_abc123",
121
+ token: "tok_xxxxx", // Solo se muestra una vez
122
+ status: "active"
123
+ }
124
+ ```
125
+
126
+ ### Listar Conexiones
127
+
128
+ ```typescript
129
+ // Todas las conexiones
130
+ const connections = await client.connections.list();
131
+
132
+ // Filtrar por entity
133
+ const userConns = await client.connections.list("user_123");
134
+
135
+ // Filtrar por entity y MCP
136
+ const specific = await client.connections.list("user_123", "kommo-mcp");
137
+ ```
138
+
139
+ ### Buscar Conexion por Entity
140
+
141
+ ```typescript
142
+ const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
143
+ if (conn) {
144
+ // El usuario ya tiene conexion
145
+ }
146
+ ```
147
+
148
+ ### Revocar Conexion
149
+
150
+ ```typescript
151
+ await client.connections.revoke("conn_abc123");
152
+ ```
153
+
154
+ ### Ejecutar Herramienta
155
+
156
+ Hay dos formas de identificar la conexion:
157
+
158
+ **Opcion 1: Por entityId (recomendado)**
159
+ ```typescript
160
+ const result = await client.tools.execute({
161
+ mcpSlug: "kommo-mcp",
162
+ entityId: "user_123", // Busca la conexion automaticamente
163
+ toolName: "get_leads",
164
+ arguments: { limit: 10 }
165
+ });
166
+ ```
167
+
168
+ **Opcion 2: Por connectionId**
169
+ ```typescript
170
+ const result = await client.tools.execute({
171
+ mcpSlug: "kommo-mcp",
172
+ connectionId: "conn_abc123",
173
+ toolName: "get_leads",
174
+ arguments: { limit: 10 }
175
+ });
176
+ ```
177
+
178
+ **Respuesta:**
179
+ ```typescript
180
+ {
181
+ content: [
182
+ { type: "text", text: "[{\"id\": 1, \"name\": \"Lead 1\"}, ...]" }
183
+ ],
184
+ isError: false
185
+ }
186
+ ```
187
+
188
+ ### Listar Herramientas de un MCP
189
+
190
+ ```typescript
191
+ const tools = await client.tools.list("kommo-mcp");
192
+ // [{ name: "get_leads", description: "...", inputSchema: {...} }, ...]
193
+ ```
194
+
195
+ ## Integraciones Disponibles
196
+
197
+ | MCP | Descripcion | Credenciales |
198
+ |-----|-------------|--------------|
199
+ | `kommo-mcp` | CRM Kommo | access_token, base_domain |
200
+ | `chatwoot-mcp` | Soporte Chatwoot | chatwoot_url, api_token, account_id |
201
+ | `notebooklm-mcp` | Google NotebookLM | notebook_url, login_email, login_password |
202
+ | `mercadopago-mcp` | Pagos MercadoPago | access_token |
203
+ | `tiendanube-mcp` | E-commerce TiendaNube | access_token, store_id |
204
+ | `correoargentino-mcp` | Envios Correo Argentino | api_key, environment |
205
+ | `arca-mcp` | Facturacion AFIP | cuit, certificate, private_key, environment |
206
+
207
+ ## Ejemplo Completo
208
+
209
+ ```typescript
210
+ import { HornerosSSP } from "hornerosssp";
211
+
212
+ const client = new HornerosSSP({ apiKey: process.env.HORNEROS_API_KEY });
213
+
214
+ async function connectUserToKommo(userId: string, kommoToken: string, domain: string) {
215
+ // Verificar si ya existe conexion
216
+ const existing = await client.connections.getByEntity(userId, "kommo-mcp");
217
+ if (existing) {
218
+ console.log("Usuario ya conectado a Kommo");
219
+ return existing;
220
+ }
221
+
222
+ // Crear nueva conexion
223
+ const conn = await client.connections.initiate({
224
+ mcpSlug: "kommo-mcp",
225
+ entityId: userId,
226
+ credentials: {
227
+ access_token: kommoToken,
228
+ base_domain: domain
229
+ }
230
+ });
231
+
232
+ console.log("Conexion creada:", conn.id);
233
+ return conn;
234
+ }
235
+
236
+ async function getLeadsForUser(userId: string) {
237
+ const result = await client.tools.execute({
238
+ mcpSlug: "kommo-mcp",
239
+ entityId: userId,
240
+ toolName: "get_leads",
241
+ arguments: { limit: 50 }
242
+ });
243
+
244
+ const leads = JSON.parse(result.content[0].text);
245
+ return leads;
246
+ }
247
+
248
+ // Uso
249
+ await connectUserToKommo("user_123", "kommo_token", "empresa.kommo.com");
250
+ const leads = await getLeadsForUser("user_123");
251
+ console.log(`Found ${leads.length} leads`);
252
+ ```
253
+
254
+ ## Manejo de Errores
255
+
256
+ ```typescript
257
+ import { HornerosError, HORNEROS_SDK_ERROR_CODES } from "hornerosssp";
258
+
259
+ try {
260
+ await client.tools.execute({...});
261
+ } catch (error) {
262
+ if (error instanceof HornerosError) {
263
+ switch (error.errorCode) {
264
+ case HORNEROS_SDK_ERROR_CODES.COMMON.CONNECTION_NOT_FOUND:
265
+ console.log("El usuario no tiene conexion. Crear una primero.");
266
+ break;
267
+ case HORNEROS_SDK_ERROR_CODES.COMMON.TOOL_NOT_FOUND:
268
+ console.log("Herramienta no existe");
269
+ break;
270
+ case HORNEROS_SDK_ERROR_CODES.COMMON.RATE_LIMITED:
271
+ console.log("Limite de requests alcanzado");
272
+ break;
273
+ default:
274
+ console.log("Error:", error.message);
275
+ }
276
+ }
277
+ }
278
+ ```
279
+
280
+ ## Variables de Entorno
281
+
282
+ El SDK puede leer configuracion de variables de entorno:
283
+
284
+ ```bash
285
+ HORNEROS_API_KEY=hsp_xxx # API key
286
+ HORNEROS_BASE_URL=https://... # URL base (opcional)
287
+ ```
288
+
289
+ ```typescript
290
+ // Si las variables estan configuradas, no necesitas pasarlas
291
+ const client = new HornerosSSP();
292
+ ```
293
+
294
+ ## TypeScript
295
+
296
+ El SDK incluye tipos TypeScript completos:
297
+
298
+ ```typescript
299
+ import type {
300
+ McpInfo,
301
+ McpDetail,
302
+ ConnectionInfo,
303
+ ToolDefinition,
304
+ ToolResult,
305
+ InitiateConnectionParams,
306
+ ExecuteToolParams
307
+ } from "hornerosssp";
308
+ ```
package/dist/index.d.mts CHANGED
@@ -4,7 +4,9 @@ interface McpInfo {
4
4
  description: string | null;
5
5
  requiredCredentials: string[];
6
6
  toolCount: number;
7
- activeConnections: number;
7
+ category: string;
8
+ logoUrl: string;
9
+ color: string;
8
10
  }
9
11
  interface McpDetail extends McpInfo {
10
12
  tools: {
@@ -16,8 +18,8 @@ interface ConnectionInfo {
16
18
  id: string;
17
19
  mcpSlug: string;
18
20
  mcpName: string;
21
+ entityId: string | null;
19
22
  appName: string | null;
20
- userId: string | null;
21
23
  mcpUrl: string;
22
24
  token: string;
23
25
  status: "active" | "revoked";
@@ -27,16 +29,35 @@ interface ConnectionInfo {
27
29
  }
28
30
  interface ConnectionRequestData {
29
31
  id: string;
32
+ mcpSlug: string;
33
+ entityId: string;
30
34
  mcpUrl: string | null;
31
35
  token: string | null;
32
36
  redirectUrl: string | null;
33
37
  status: "active" | "pending";
34
38
  }
39
+ /**
40
+ * Parameters for creating a connection.
41
+ *
42
+ * - entityId: REQUIRED - The ID of the end user in YOUR app.
43
+ * This is how you identify which user the connection belongs to.
44
+ *
45
+ * - mcpSlug: REQUIRED - The MCP to connect to (e.g., "kommo-mcp")
46
+ *
47
+ * - credentials: REQUIRED - The credentials for the MCP
48
+ *
49
+ * - appName: Optional - A name for this connection
50
+ */
35
51
  interface InitiateConnectionParams {
52
+ /** The MCP to connect to (e.g., "kommo-mcp") */
36
53
  mcpSlug: string;
54
+ /** REQUIRED: The ID of the end user in YOUR app */
55
+ entityId: string;
56
+ /** Optional: A name for this connection */
37
57
  appName?: string;
38
- userId?: string;
58
+ /** The credentials for the MCP */
39
59
  credentials?: Record<string, string>;
60
+ /** Optional: Auth scheme for OAuth flows */
40
61
  authScheme?: ConnectionData;
41
62
  }
42
63
  interface ToolDefinition {
@@ -55,11 +76,26 @@ interface ToolResult {
55
76
  }>;
56
77
  isError?: boolean;
57
78
  }
79
+ /**
80
+ * Parameters for executing a tool.
81
+ *
82
+ * You can identify the connection in two ways:
83
+ * 1. By connectionId: The ID returned when creating a connection
84
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
85
+ *
86
+ * At least one of connectionId or entityId must be provided.
87
+ */
58
88
  interface ExecuteToolParams {
89
+ /** The MCP to use (e.g., "kommo-mcp") */
59
90
  mcpSlug: string;
60
- connectionId: string;
91
+ /** The tool to execute */
61
92
  toolName: string;
93
+ /** Arguments to pass to the tool */
62
94
  arguments: Record<string, unknown>;
95
+ /** Option 1: The connection ID */
96
+ connectionId?: string;
97
+ /** Option 2: The entity ID (end user ID in your app) - will find connection automatically */
98
+ entityId?: string;
63
99
  }
64
100
  interface ConnectionData {
65
101
  type: string;
@@ -90,6 +126,8 @@ declare class Mcps {
90
126
  declare class ConnectionRequest {
91
127
  private client;
92
128
  readonly id: string;
129
+ readonly mcpSlug: string;
130
+ readonly entityId: string;
93
131
  readonly mcpUrl: string | null;
94
132
  readonly token: string | null;
95
133
  readonly redirectUrl: string | null;
@@ -106,16 +144,88 @@ declare class ConnectionRequest {
106
144
  declare class Connections {
107
145
  private client;
108
146
  constructor(client: HornerosSSP);
147
+ /**
148
+ * Create a connection for an end user (entity).
149
+ *
150
+ * @param params.mcpSlug - The MCP to connect to (e.g., "kommo-mcp")
151
+ * @param params.entityId - REQUIRED: The ID of the end user in YOUR app
152
+ * @param params.credentials - The credentials for the MCP
153
+ * @param params.appName - Optional name for this connection
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const conn = await client.connections.initiate({
158
+ * mcpSlug: "kommo-mcp",
159
+ * entityId: "user_123",
160
+ * credentials: { access_token: "...", base_domain: "..." }
161
+ * });
162
+ * ```
163
+ */
109
164
  initiate(params: InitiateConnectionParams): Promise<ConnectionRequest>;
110
- list(): Promise<ConnectionInfo[]>;
165
+ /**
166
+ * List all connections.
167
+ *
168
+ * @param entityId - Optional: Filter by entity ID
169
+ * @param mcpSlug - Optional: Filter by MCP slug
170
+ */
171
+ list(entityId?: string, mcpSlug?: string): Promise<ConnectionInfo[]>;
172
+ /**
173
+ * Get a connection by ID.
174
+ */
111
175
  get(id: string): Promise<ConnectionInfo>;
176
+ /**
177
+ * Get a connection by entity ID and MCP slug.
178
+ * Returns null if not found.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
183
+ * if (conn) {
184
+ * // Connection exists, can execute tools
185
+ * }
186
+ * ```
187
+ */
188
+ getByEntity(entityId: string, mcpSlug: string): Promise<ConnectionInfo | null>;
189
+ /**
190
+ * Revoke a connection by ID.
191
+ */
112
192
  revoke(id: string): Promise<void>;
113
193
  }
114
194
 
115
195
  declare class Tools {
116
196
  private client;
117
197
  constructor(client: HornerosSSP);
198
+ /**
199
+ * List all tools available for an MCP.
200
+ */
118
201
  list(mcpSlug: string): Promise<ToolDefinition[]>;
202
+ /**
203
+ * Execute a tool on an MCP.
204
+ *
205
+ * You can identify the connection in two ways:
206
+ * 1. By connectionId: The ID returned when creating a connection
207
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
208
+ *
209
+ * @example Using entityId (recommended)
210
+ * ```typescript
211
+ * const result = await client.tools.execute({
212
+ * mcpSlug: "kommo-mcp",
213
+ * entityId: "user_123",
214
+ * toolName: "get_leads",
215
+ * arguments: { limit: 10 }
216
+ * });
217
+ * ```
218
+ *
219
+ * @example Using connectionId
220
+ * ```typescript
221
+ * const result = await client.tools.execute({
222
+ * mcpSlug: "kommo-mcp",
223
+ * connectionId: "conn_abc123",
224
+ * toolName: "get_leads",
225
+ * arguments: { limit: 10 }
226
+ * });
227
+ * ```
228
+ */
119
229
  execute(params: ExecuteToolParams): Promise<ToolResult>;
120
230
  }
121
231
 
@@ -165,6 +275,7 @@ declare const HORNEROS_SDK_ERROR_CODES: {
165
275
  readonly BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE";
166
276
  readonly UNKNOWN: "COMMON::UNKNOWN";
167
277
  readonly INVALID_PARAMS: "COMMON::INVALID_PARAMS";
278
+ readonly VALIDATION_ERROR: "COMMON::VALIDATION_ERROR";
168
279
  };
169
280
  readonly SDK: {
170
281
  readonly NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT";
package/dist/index.d.ts CHANGED
@@ -4,7 +4,9 @@ interface McpInfo {
4
4
  description: string | null;
5
5
  requiredCredentials: string[];
6
6
  toolCount: number;
7
- activeConnections: number;
7
+ category: string;
8
+ logoUrl: string;
9
+ color: string;
8
10
  }
9
11
  interface McpDetail extends McpInfo {
10
12
  tools: {
@@ -16,8 +18,8 @@ interface ConnectionInfo {
16
18
  id: string;
17
19
  mcpSlug: string;
18
20
  mcpName: string;
21
+ entityId: string | null;
19
22
  appName: string | null;
20
- userId: string | null;
21
23
  mcpUrl: string;
22
24
  token: string;
23
25
  status: "active" | "revoked";
@@ -27,16 +29,35 @@ interface ConnectionInfo {
27
29
  }
28
30
  interface ConnectionRequestData {
29
31
  id: string;
32
+ mcpSlug: string;
33
+ entityId: string;
30
34
  mcpUrl: string | null;
31
35
  token: string | null;
32
36
  redirectUrl: string | null;
33
37
  status: "active" | "pending";
34
38
  }
39
+ /**
40
+ * Parameters for creating a connection.
41
+ *
42
+ * - entityId: REQUIRED - The ID of the end user in YOUR app.
43
+ * This is how you identify which user the connection belongs to.
44
+ *
45
+ * - mcpSlug: REQUIRED - The MCP to connect to (e.g., "kommo-mcp")
46
+ *
47
+ * - credentials: REQUIRED - The credentials for the MCP
48
+ *
49
+ * - appName: Optional - A name for this connection
50
+ */
35
51
  interface InitiateConnectionParams {
52
+ /** The MCP to connect to (e.g., "kommo-mcp") */
36
53
  mcpSlug: string;
54
+ /** REQUIRED: The ID of the end user in YOUR app */
55
+ entityId: string;
56
+ /** Optional: A name for this connection */
37
57
  appName?: string;
38
- userId?: string;
58
+ /** The credentials for the MCP */
39
59
  credentials?: Record<string, string>;
60
+ /** Optional: Auth scheme for OAuth flows */
40
61
  authScheme?: ConnectionData;
41
62
  }
42
63
  interface ToolDefinition {
@@ -55,11 +76,26 @@ interface ToolResult {
55
76
  }>;
56
77
  isError?: boolean;
57
78
  }
79
+ /**
80
+ * Parameters for executing a tool.
81
+ *
82
+ * You can identify the connection in two ways:
83
+ * 1. By connectionId: The ID returned when creating a connection
84
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
85
+ *
86
+ * At least one of connectionId or entityId must be provided.
87
+ */
58
88
  interface ExecuteToolParams {
89
+ /** The MCP to use (e.g., "kommo-mcp") */
59
90
  mcpSlug: string;
60
- connectionId: string;
91
+ /** The tool to execute */
61
92
  toolName: string;
93
+ /** Arguments to pass to the tool */
62
94
  arguments: Record<string, unknown>;
95
+ /** Option 1: The connection ID */
96
+ connectionId?: string;
97
+ /** Option 2: The entity ID (end user ID in your app) - will find connection automatically */
98
+ entityId?: string;
63
99
  }
64
100
  interface ConnectionData {
65
101
  type: string;
@@ -90,6 +126,8 @@ declare class Mcps {
90
126
  declare class ConnectionRequest {
91
127
  private client;
92
128
  readonly id: string;
129
+ readonly mcpSlug: string;
130
+ readonly entityId: string;
93
131
  readonly mcpUrl: string | null;
94
132
  readonly token: string | null;
95
133
  readonly redirectUrl: string | null;
@@ -106,16 +144,88 @@ declare class ConnectionRequest {
106
144
  declare class Connections {
107
145
  private client;
108
146
  constructor(client: HornerosSSP);
147
+ /**
148
+ * Create a connection for an end user (entity).
149
+ *
150
+ * @param params.mcpSlug - The MCP to connect to (e.g., "kommo-mcp")
151
+ * @param params.entityId - REQUIRED: The ID of the end user in YOUR app
152
+ * @param params.credentials - The credentials for the MCP
153
+ * @param params.appName - Optional name for this connection
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const conn = await client.connections.initiate({
158
+ * mcpSlug: "kommo-mcp",
159
+ * entityId: "user_123",
160
+ * credentials: { access_token: "...", base_domain: "..." }
161
+ * });
162
+ * ```
163
+ */
109
164
  initiate(params: InitiateConnectionParams): Promise<ConnectionRequest>;
110
- list(): Promise<ConnectionInfo[]>;
165
+ /**
166
+ * List all connections.
167
+ *
168
+ * @param entityId - Optional: Filter by entity ID
169
+ * @param mcpSlug - Optional: Filter by MCP slug
170
+ */
171
+ list(entityId?: string, mcpSlug?: string): Promise<ConnectionInfo[]>;
172
+ /**
173
+ * Get a connection by ID.
174
+ */
111
175
  get(id: string): Promise<ConnectionInfo>;
176
+ /**
177
+ * Get a connection by entity ID and MCP slug.
178
+ * Returns null if not found.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
183
+ * if (conn) {
184
+ * // Connection exists, can execute tools
185
+ * }
186
+ * ```
187
+ */
188
+ getByEntity(entityId: string, mcpSlug: string): Promise<ConnectionInfo | null>;
189
+ /**
190
+ * Revoke a connection by ID.
191
+ */
112
192
  revoke(id: string): Promise<void>;
113
193
  }
114
194
 
115
195
  declare class Tools {
116
196
  private client;
117
197
  constructor(client: HornerosSSP);
198
+ /**
199
+ * List all tools available for an MCP.
200
+ */
118
201
  list(mcpSlug: string): Promise<ToolDefinition[]>;
202
+ /**
203
+ * Execute a tool on an MCP.
204
+ *
205
+ * You can identify the connection in two ways:
206
+ * 1. By connectionId: The ID returned when creating a connection
207
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
208
+ *
209
+ * @example Using entityId (recommended)
210
+ * ```typescript
211
+ * const result = await client.tools.execute({
212
+ * mcpSlug: "kommo-mcp",
213
+ * entityId: "user_123",
214
+ * toolName: "get_leads",
215
+ * arguments: { limit: 10 }
216
+ * });
217
+ * ```
218
+ *
219
+ * @example Using connectionId
220
+ * ```typescript
221
+ * const result = await client.tools.execute({
222
+ * mcpSlug: "kommo-mcp",
223
+ * connectionId: "conn_abc123",
224
+ * toolName: "get_leads",
225
+ * arguments: { limit: 10 }
226
+ * });
227
+ * ```
228
+ */
119
229
  execute(params: ExecuteToolParams): Promise<ToolResult>;
120
230
  }
121
231
 
@@ -165,6 +275,7 @@ declare const HORNEROS_SDK_ERROR_CODES: {
165
275
  readonly BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE";
166
276
  readonly UNKNOWN: "COMMON::UNKNOWN";
167
277
  readonly INVALID_PARAMS: "COMMON::INVALID_PARAMS";
278
+ readonly VALIDATION_ERROR: "COMMON::VALIDATION_ERROR";
168
279
  };
169
280
  readonly SDK: {
170
281
  readonly NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT";
package/dist/index.js CHANGED
@@ -49,7 +49,8 @@ var HORNEROS_SDK_ERROR_CODES = {
49
49
  API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE",
50
50
  BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE",
51
51
  UNKNOWN: "COMMON::UNKNOWN",
52
- INVALID_PARAMS: "COMMON::INVALID_PARAMS"
52
+ INVALID_PARAMS: "COMMON::INVALID_PARAMS",
53
+ VALIDATION_ERROR: "COMMON::VALIDATION_ERROR"
53
54
  },
54
55
  SDK: {
55
56
  NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT",
@@ -132,6 +133,8 @@ var ConnectionRequest = class {
132
133
  constructor(client, data) {
133
134
  this.client = client;
134
135
  this.id = data.id;
136
+ this.mcpSlug = data.mcpSlug;
137
+ this.entityId = data.entityId;
135
138
  this.mcpUrl = data.mcpUrl;
136
139
  this.token = data.token;
137
140
  this.redirectUrl = data.redirectUrl;
@@ -171,12 +174,36 @@ var Connections = class {
171
174
  constructor(client) {
172
175
  this.client = client;
173
176
  }
177
+ /**
178
+ * Create a connection for an end user (entity).
179
+ *
180
+ * @param params.mcpSlug - The MCP to connect to (e.g., "kommo-mcp")
181
+ * @param params.entityId - REQUIRED: The ID of the end user in YOUR app
182
+ * @param params.credentials - The credentials for the MCP
183
+ * @param params.appName - Optional name for this connection
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * const conn = await client.connections.initiate({
188
+ * mcpSlug: "kommo-mcp",
189
+ * entityId: "user_123",
190
+ * credentials: { access_token: "...", base_domain: "..." }
191
+ * });
192
+ * ```
193
+ */
174
194
  async initiate(params) {
195
+ if (!params.entityId) {
196
+ throw new HornerosError(
197
+ HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,
198
+ "entityId is required. This identifies the end user in your app.",
199
+ 400
200
+ );
201
+ }
175
202
  const body = {
176
- mcp_slug: params.mcpSlug
203
+ mcp_slug: params.mcpSlug,
204
+ entity_id: params.entityId
177
205
  };
178
206
  if (params.appName) body.app_name = params.appName;
179
- if (params.userId) body.user_id = params.userId;
180
207
  if (params.credentials) body.credentials = params.credentials;
181
208
  if (params.authScheme) body.auth_scheme = params.authScheme;
182
209
  const res = await this.client.fetch(
@@ -185,16 +212,53 @@ var Connections = class {
185
212
  );
186
213
  return new ConnectionRequest(this.client, res.data);
187
214
  }
188
- async list() {
189
- const res = await this.client.fetch("/connections");
215
+ /**
216
+ * List all connections.
217
+ *
218
+ * @param entityId - Optional: Filter by entity ID
219
+ * @param mcpSlug - Optional: Filter by MCP slug
220
+ */
221
+ async list(entityId, mcpSlug) {
222
+ const params = new URLSearchParams();
223
+ if (entityId) params.set("entity_id", entityId);
224
+ if (mcpSlug) params.set("mcp_slug", mcpSlug);
225
+ const query = params.toString();
226
+ const path = query ? `/connections?${query}` : "/connections";
227
+ const res = await this.client.fetch(path);
190
228
  return res.data;
191
229
  }
230
+ /**
231
+ * Get a connection by ID.
232
+ */
192
233
  async get(id) {
193
234
  const res = await this.client.fetch(
194
235
  `/connections/${encodeURIComponent(id)}`
195
236
  );
196
237
  return res.data;
197
238
  }
239
+ /**
240
+ * Get a connection by entity ID and MCP slug.
241
+ * Returns null if not found.
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
246
+ * if (conn) {
247
+ * // Connection exists, can execute tools
248
+ * }
249
+ * ```
250
+ */
251
+ async getByEntity(entityId, mcpSlug) {
252
+ try {
253
+ const connections = await this.list(entityId, mcpSlug);
254
+ return connections[0] || null;
255
+ } catch {
256
+ return null;
257
+ }
258
+ }
259
+ /**
260
+ * Revoke a connection by ID.
261
+ */
198
262
  async revoke(id) {
199
263
  await this.client.fetch(
200
264
  `/connections/${encodeURIComponent(id)}`,
@@ -211,23 +275,65 @@ var Tools = class {
211
275
  constructor(client) {
212
276
  this.client = client;
213
277
  }
278
+ /**
279
+ * List all tools available for an MCP.
280
+ */
214
281
  async list(mcpSlug) {
215
282
  const res = await this.client.fetch(
216
283
  `/mcps/${encodeURIComponent(mcpSlug)}/tools`
217
284
  );
218
285
  return res.data;
219
286
  }
287
+ /**
288
+ * Execute a tool on an MCP.
289
+ *
290
+ * You can identify the connection in two ways:
291
+ * 1. By connectionId: The ID returned when creating a connection
292
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
293
+ *
294
+ * @example Using entityId (recommended)
295
+ * ```typescript
296
+ * const result = await client.tools.execute({
297
+ * mcpSlug: "kommo-mcp",
298
+ * entityId: "user_123",
299
+ * toolName: "get_leads",
300
+ * arguments: { limit: 10 }
301
+ * });
302
+ * ```
303
+ *
304
+ * @example Using connectionId
305
+ * ```typescript
306
+ * const result = await client.tools.execute({
307
+ * mcpSlug: "kommo-mcp",
308
+ * connectionId: "conn_abc123",
309
+ * toolName: "get_leads",
310
+ * arguments: { limit: 10 }
311
+ * });
312
+ * ```
313
+ */
220
314
  async execute(params) {
315
+ if (!params.connectionId && !params.entityId) {
316
+ throw new HornerosError(
317
+ HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,
318
+ "Either connectionId or entityId is required",
319
+ 400
320
+ );
321
+ }
322
+ const body = {
323
+ mcp_slug: params.mcpSlug,
324
+ tool_name: params.toolName,
325
+ arguments: params.arguments
326
+ };
327
+ if (params.entityId) {
328
+ body.entity_id = params.entityId;
329
+ } else if (params.connectionId) {
330
+ body.connection_id = params.connectionId;
331
+ }
221
332
  const res = await this.client.fetch(
222
333
  "/tools/execute",
223
334
  {
224
335
  method: "POST",
225
- body: JSON.stringify({
226
- mcp_slug: params.mcpSlug,
227
- connection_id: params.connectionId,
228
- tool_name: params.toolName,
229
- arguments: params.arguments
230
- })
336
+ body: JSON.stringify(body)
231
337
  }
232
338
  );
233
339
  return res.data;
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 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":[]}
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 VALIDATION_ERROR: \"COMMON::VALIDATION_ERROR\",\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, HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpSlug: string;\n public readonly entityId: 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.mcpSlug = data.mcpSlug;\n this.entityId = data.entityId;\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 /**\n * Create a connection for an end user (entity).\n *\n * @param params.mcpSlug - The MCP to connect to (e.g., \"kommo-mcp\")\n * @param params.entityId - REQUIRED: The ID of the end user in YOUR app\n * @param params.credentials - The credentials for the MCP\n * @param params.appName - Optional name for this connection\n *\n * @example\n * ```typescript\n * const conn = await client.connections.initiate({\n * mcpSlug: \"kommo-mcp\",\n * entityId: \"user_123\",\n * credentials: { access_token: \"...\", base_domain: \"...\" }\n * });\n * ```\n */\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n // Validate entityId is provided\n if (!params.entityId) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,\n \"entityId is required. This identifies the end user in your app.\",\n 400\n );\n }\n\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n entity_id: params.entityId,\n };\n\n if (params.appName) body.app_name = params.appName;\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 /**\n * List all connections.\n *\n * @param entityId - Optional: Filter by entity ID\n * @param mcpSlug - Optional: Filter by MCP slug\n */\n async list(entityId?: string, mcpSlug?: string): Promise<ConnectionInfo[]> {\n const params = new URLSearchParams();\n if (entityId) params.set(\"entity_id\", entityId);\n if (mcpSlug) params.set(\"mcp_slug\", mcpSlug);\n\n const query = params.toString();\n const path = query ? `/connections?${query}` : \"/connections\";\n\n const res = await this.client.fetch<ApiResponse<ConnectionInfo[]>>(path);\n return res.data;\n }\n\n /**\n * Get a connection by ID.\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 /**\n * Get a connection by entity ID and MCP slug.\n * Returns null if not found.\n *\n * @example\n * ```typescript\n * const conn = await client.connections.getByEntity(\"user_123\", \"kommo-mcp\");\n * if (conn) {\n * // Connection exists, can execute tools\n * }\n * ```\n */\n async getByEntity(entityId: string, mcpSlug: string): Promise<ConnectionInfo | null> {\n try {\n const connections = await this.list(entityId, mcpSlug);\n return connections[0] || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Revoke a connection by ID.\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\";\nimport { HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n /**\n * List all tools available for an MCP.\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 /**\n * Execute a tool on an MCP.\n *\n * You can identify the connection in two ways:\n * 1. By connectionId: The ID returned when creating a connection\n * 2. By entityId: The ID of the end user (will find the connection automatically)\n *\n * @example Using entityId (recommended)\n * ```typescript\n * const result = await client.tools.execute({\n * mcpSlug: \"kommo-mcp\",\n * entityId: \"user_123\",\n * toolName: \"get_leads\",\n * arguments: { limit: 10 }\n * });\n * ```\n *\n * @example Using connectionId\n * ```typescript\n * const result = await client.tools.execute({\n * mcpSlug: \"kommo-mcp\",\n * connectionId: \"conn_abc123\",\n * toolName: \"get_leads\",\n * arguments: { limit: 10 }\n * });\n * ```\n */\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n // Validate that at least one of connectionId or entityId is provided\n if (!params.connectionId && !params.entityId) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,\n \"Either connectionId or entityId is required\",\n 400\n );\n }\n\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n tool_name: params.toolName,\n arguments: params.arguments,\n };\n\n // Prefer entityId if provided\n if (params.entityId) {\n body.entity_id = params.entityId;\n } else if (params.connectionId) {\n body.connection_id = params.connectionId;\n }\n\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify(body),\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
@@ -13,7 +13,8 @@ var HORNEROS_SDK_ERROR_CODES = {
13
13
  API_KEY_UNAVAILABLE: "COMMON::API_KEY_UNAVAILABLE",
14
14
  BASE_URL_NOT_REACHABLE: "COMMON::BASE_URL_NOT_REACHABLE",
15
15
  UNKNOWN: "COMMON::UNKNOWN",
16
- INVALID_PARAMS: "COMMON::INVALID_PARAMS"
16
+ INVALID_PARAMS: "COMMON::INVALID_PARAMS",
17
+ VALIDATION_ERROR: "COMMON::VALIDATION_ERROR"
17
18
  },
18
19
  SDK: {
19
20
  NO_CONNECTED_ACCOUNT: "SDK::NO_CONNECTED_ACCOUNT",
@@ -96,6 +97,8 @@ var ConnectionRequest = class {
96
97
  constructor(client, data) {
97
98
  this.client = client;
98
99
  this.id = data.id;
100
+ this.mcpSlug = data.mcpSlug;
101
+ this.entityId = data.entityId;
99
102
  this.mcpUrl = data.mcpUrl;
100
103
  this.token = data.token;
101
104
  this.redirectUrl = data.redirectUrl;
@@ -135,12 +138,36 @@ var Connections = class {
135
138
  constructor(client) {
136
139
  this.client = client;
137
140
  }
141
+ /**
142
+ * Create a connection for an end user (entity).
143
+ *
144
+ * @param params.mcpSlug - The MCP to connect to (e.g., "kommo-mcp")
145
+ * @param params.entityId - REQUIRED: The ID of the end user in YOUR app
146
+ * @param params.credentials - The credentials for the MCP
147
+ * @param params.appName - Optional name for this connection
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const conn = await client.connections.initiate({
152
+ * mcpSlug: "kommo-mcp",
153
+ * entityId: "user_123",
154
+ * credentials: { access_token: "...", base_domain: "..." }
155
+ * });
156
+ * ```
157
+ */
138
158
  async initiate(params) {
159
+ if (!params.entityId) {
160
+ throw new HornerosError(
161
+ HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,
162
+ "entityId is required. This identifies the end user in your app.",
163
+ 400
164
+ );
165
+ }
139
166
  const body = {
140
- mcp_slug: params.mcpSlug
167
+ mcp_slug: params.mcpSlug,
168
+ entity_id: params.entityId
141
169
  };
142
170
  if (params.appName) body.app_name = params.appName;
143
- if (params.userId) body.user_id = params.userId;
144
171
  if (params.credentials) body.credentials = params.credentials;
145
172
  if (params.authScheme) body.auth_scheme = params.authScheme;
146
173
  const res = await this.client.fetch(
@@ -149,16 +176,53 @@ var Connections = class {
149
176
  );
150
177
  return new ConnectionRequest(this.client, res.data);
151
178
  }
152
- async list() {
153
- const res = await this.client.fetch("/connections");
179
+ /**
180
+ * List all connections.
181
+ *
182
+ * @param entityId - Optional: Filter by entity ID
183
+ * @param mcpSlug - Optional: Filter by MCP slug
184
+ */
185
+ async list(entityId, mcpSlug) {
186
+ const params = new URLSearchParams();
187
+ if (entityId) params.set("entity_id", entityId);
188
+ if (mcpSlug) params.set("mcp_slug", mcpSlug);
189
+ const query = params.toString();
190
+ const path = query ? `/connections?${query}` : "/connections";
191
+ const res = await this.client.fetch(path);
154
192
  return res.data;
155
193
  }
194
+ /**
195
+ * Get a connection by ID.
196
+ */
156
197
  async get(id) {
157
198
  const res = await this.client.fetch(
158
199
  `/connections/${encodeURIComponent(id)}`
159
200
  );
160
201
  return res.data;
161
202
  }
203
+ /**
204
+ * Get a connection by entity ID and MCP slug.
205
+ * Returns null if not found.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
210
+ * if (conn) {
211
+ * // Connection exists, can execute tools
212
+ * }
213
+ * ```
214
+ */
215
+ async getByEntity(entityId, mcpSlug) {
216
+ try {
217
+ const connections = await this.list(entityId, mcpSlug);
218
+ return connections[0] || null;
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
223
+ /**
224
+ * Revoke a connection by ID.
225
+ */
162
226
  async revoke(id) {
163
227
  await this.client.fetch(
164
228
  `/connections/${encodeURIComponent(id)}`,
@@ -175,23 +239,65 @@ var Tools = class {
175
239
  constructor(client) {
176
240
  this.client = client;
177
241
  }
242
+ /**
243
+ * List all tools available for an MCP.
244
+ */
178
245
  async list(mcpSlug) {
179
246
  const res = await this.client.fetch(
180
247
  `/mcps/${encodeURIComponent(mcpSlug)}/tools`
181
248
  );
182
249
  return res.data;
183
250
  }
251
+ /**
252
+ * Execute a tool on an MCP.
253
+ *
254
+ * You can identify the connection in two ways:
255
+ * 1. By connectionId: The ID returned when creating a connection
256
+ * 2. By entityId: The ID of the end user (will find the connection automatically)
257
+ *
258
+ * @example Using entityId (recommended)
259
+ * ```typescript
260
+ * const result = await client.tools.execute({
261
+ * mcpSlug: "kommo-mcp",
262
+ * entityId: "user_123",
263
+ * toolName: "get_leads",
264
+ * arguments: { limit: 10 }
265
+ * });
266
+ * ```
267
+ *
268
+ * @example Using connectionId
269
+ * ```typescript
270
+ * const result = await client.tools.execute({
271
+ * mcpSlug: "kommo-mcp",
272
+ * connectionId: "conn_abc123",
273
+ * toolName: "get_leads",
274
+ * arguments: { limit: 10 }
275
+ * });
276
+ * ```
277
+ */
184
278
  async execute(params) {
279
+ if (!params.connectionId && !params.entityId) {
280
+ throw new HornerosError(
281
+ HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,
282
+ "Either connectionId or entityId is required",
283
+ 400
284
+ );
285
+ }
286
+ const body = {
287
+ mcp_slug: params.mcpSlug,
288
+ tool_name: params.toolName,
289
+ arguments: params.arguments
290
+ };
291
+ if (params.entityId) {
292
+ body.entity_id = params.entityId;
293
+ } else if (params.connectionId) {
294
+ body.connection_id = params.connectionId;
295
+ }
185
296
  const res = await this.client.fetch(
186
297
  "/tools/execute",
187
298
  {
188
299
  method: "POST",
189
- body: JSON.stringify({
190
- mcp_slug: params.mcpSlug,
191
- connection_id: params.connectionId,
192
- tool_name: params.toolName,
193
- arguments: params.arguments
194
- })
300
+ body: JSON.stringify(body)
195
301
  }
196
302
  );
197
303
  return res.data;
@@ -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":["// ── 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":[]}
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 VALIDATION_ERROR: \"COMMON::VALIDATION_ERROR\",\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, HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\n\nexport class ConnectionRequest {\n public readonly id: string;\n public readonly mcpSlug: string;\n public readonly entityId: 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.mcpSlug = data.mcpSlug;\n this.entityId = data.entityId;\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 /**\n * Create a connection for an end user (entity).\n *\n * @param params.mcpSlug - The MCP to connect to (e.g., \"kommo-mcp\")\n * @param params.entityId - REQUIRED: The ID of the end user in YOUR app\n * @param params.credentials - The credentials for the MCP\n * @param params.appName - Optional name for this connection\n *\n * @example\n * ```typescript\n * const conn = await client.connections.initiate({\n * mcpSlug: \"kommo-mcp\",\n * entityId: \"user_123\",\n * credentials: { access_token: \"...\", base_domain: \"...\" }\n * });\n * ```\n */\n async initiate(params: InitiateConnectionParams): Promise<ConnectionRequest> {\n // Validate entityId is provided\n if (!params.entityId) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,\n \"entityId is required. This identifies the end user in your app.\",\n 400\n );\n }\n\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n entity_id: params.entityId,\n };\n\n if (params.appName) body.app_name = params.appName;\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 /**\n * List all connections.\n *\n * @param entityId - Optional: Filter by entity ID\n * @param mcpSlug - Optional: Filter by MCP slug\n */\n async list(entityId?: string, mcpSlug?: string): Promise<ConnectionInfo[]> {\n const params = new URLSearchParams();\n if (entityId) params.set(\"entity_id\", entityId);\n if (mcpSlug) params.set(\"mcp_slug\", mcpSlug);\n\n const query = params.toString();\n const path = query ? `/connections?${query}` : \"/connections\";\n\n const res = await this.client.fetch<ApiResponse<ConnectionInfo[]>>(path);\n return res.data;\n }\n\n /**\n * Get a connection by ID.\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 /**\n * Get a connection by entity ID and MCP slug.\n * Returns null if not found.\n *\n * @example\n * ```typescript\n * const conn = await client.connections.getByEntity(\"user_123\", \"kommo-mcp\");\n * if (conn) {\n * // Connection exists, can execute tools\n * }\n * ```\n */\n async getByEntity(entityId: string, mcpSlug: string): Promise<ConnectionInfo | null> {\n try {\n const connections = await this.list(entityId, mcpSlug);\n return connections[0] || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Revoke a connection by ID.\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\";\nimport { HornerosError, HORNEROS_SDK_ERROR_CODES } from \"./errors\";\n\nexport class Tools {\n constructor(private client: HornerosSSP) {}\n\n /**\n * List all tools available for an MCP.\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 /**\n * Execute a tool on an MCP.\n *\n * You can identify the connection in two ways:\n * 1. By connectionId: The ID returned when creating a connection\n * 2. By entityId: The ID of the end user (will find the connection automatically)\n *\n * @example Using entityId (recommended)\n * ```typescript\n * const result = await client.tools.execute({\n * mcpSlug: \"kommo-mcp\",\n * entityId: \"user_123\",\n * toolName: \"get_leads\",\n * arguments: { limit: 10 }\n * });\n * ```\n *\n * @example Using connectionId\n * ```typescript\n * const result = await client.tools.execute({\n * mcpSlug: \"kommo-mcp\",\n * connectionId: \"conn_abc123\",\n * toolName: \"get_leads\",\n * arguments: { limit: 10 }\n * });\n * ```\n */\n async execute(params: ExecuteToolParams): Promise<ToolResult> {\n // Validate that at least one of connectionId or entityId is provided\n if (!params.connectionId && !params.entityId) {\n throw new HornerosError(\n HORNEROS_SDK_ERROR_CODES.COMMON.VALIDATION_ERROR,\n \"Either connectionId or entityId is required\",\n 400\n );\n }\n\n const body: Record<string, unknown> = {\n mcp_slug: params.mcpSlug,\n tool_name: params.toolName,\n arguments: params.arguments,\n };\n\n // Prefer entityId if provided\n if (params.entityId) {\n body.entity_id = params.entityId;\n } else if (params.connectionId) {\n body.connection_id = params.connectionId;\n }\n\n const res = await this.client.fetch<ApiResponse<ToolResult>>(\n \"/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify(body),\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,6 +1,6 @@
1
1
  {
2
2
  "name": "hornerosssp",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "SDK and CLI for HornerosSSP - integrate MCPs into any app",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",