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 +308 -0
- package/dist/index.d.mts +116 -5
- package/dist/index.d.ts +116 -5
- package/dist/index.js +117 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +117 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
189
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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;
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":[]}
|