orqo-node-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +547 -0
- package/README.pdf +0 -0
- package/dist/client.d.ts +64 -0
- package/dist/client.js +174 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/instance.d.ts +166 -0
- package/dist/instance.js +365 -0
- package/dist/types.d.ts +199 -0
- package/dist/types.js +18 -0
- package/dist/webhook-handler.d.ts +54 -0
- package/dist/webhook-handler.js +161 -0
- package/package.json +36 -0
package/dist/instance.js
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrqoInstance — Represents a single provisioned instance.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed methods for WhatsApp, Agents, Webhooks,
|
|
5
|
+
* Guardrails, Handoff, and API Bridge — scoped to a specific
|
|
6
|
+
* instance + API token.
|
|
7
|
+
*/
|
|
8
|
+
import { OrqoError } from './types.js';
|
|
9
|
+
const DEFAULT_RETRY = {
|
|
10
|
+
maxAttempts: 3,
|
|
11
|
+
backoffMs: 1000,
|
|
12
|
+
multiplier: 2,
|
|
13
|
+
retryOn: [429, 500, 502, 503, 504],
|
|
14
|
+
};
|
|
15
|
+
export class OrqoInstance {
|
|
16
|
+
instanceId;
|
|
17
|
+
host;
|
|
18
|
+
apiToken;
|
|
19
|
+
_fetch;
|
|
20
|
+
retry;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.host = config.host.replace(/\/+$/, '');
|
|
23
|
+
this.instanceId = config.instanceId;
|
|
24
|
+
this.apiToken = config.apiToken;
|
|
25
|
+
this._fetch = config.fetch ?? globalThis.fetch;
|
|
26
|
+
this.retry = { ...DEFAULT_RETRY, ...config.retry };
|
|
27
|
+
}
|
|
28
|
+
// --------------------------------------------------------------------------
|
|
29
|
+
// Private helpers
|
|
30
|
+
// --------------------------------------------------------------------------
|
|
31
|
+
async request(path, options = {}) {
|
|
32
|
+
const url = `${this.host}/api/instances/${this.instanceId}${path}`;
|
|
33
|
+
let lastError = null;
|
|
34
|
+
for (let attempt = 0; attempt <= this.retry.maxAttempts; attempt++) {
|
|
35
|
+
if (attempt > 0) {
|
|
36
|
+
const delay = this.retry.backoffMs * Math.pow(this.retry.multiplier, attempt - 1);
|
|
37
|
+
await new Promise(r => setTimeout(r, delay));
|
|
38
|
+
}
|
|
39
|
+
const res = await this._fetch(url, {
|
|
40
|
+
...options,
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'Authorization': `Bearer ${this.apiToken}`,
|
|
44
|
+
...options.headers,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
const body = await res.json().catch(() => null);
|
|
49
|
+
lastError = new OrqoError(body?.error ?? `HTTP ${res.status}`, res.status, body);
|
|
50
|
+
// Only retry on specific status codes
|
|
51
|
+
if (this.retry.retryOn.includes(res.status) && attempt < this.retry.maxAttempts) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
throw lastError;
|
|
55
|
+
}
|
|
56
|
+
return res.json();
|
|
57
|
+
}
|
|
58
|
+
throw lastError ?? new OrqoError('Max retries exceeded', 0);
|
|
59
|
+
}
|
|
60
|
+
// --------------------------------------------------------------------------
|
|
61
|
+
// Instance Status
|
|
62
|
+
// --------------------------------------------------------------------------
|
|
63
|
+
/** Get the current status of this instance. */
|
|
64
|
+
async getStatus() {
|
|
65
|
+
return this.request('/status');
|
|
66
|
+
}
|
|
67
|
+
// --------------------------------------------------------------------------
|
|
68
|
+
// WhatsApp
|
|
69
|
+
// --------------------------------------------------------------------------
|
|
70
|
+
/** Get WhatsApp connection status and QR code (if available). */
|
|
71
|
+
async getWhatsAppStatus() {
|
|
72
|
+
return this.request('/whatsapp/status');
|
|
73
|
+
}
|
|
74
|
+
/** Start the WhatsApp socket (begins QR code generation). */
|
|
75
|
+
async connectWhatsApp() {
|
|
76
|
+
return this.request('/whatsapp/connect', { method: 'POST' });
|
|
77
|
+
}
|
|
78
|
+
/** Disconnect WhatsApp. */
|
|
79
|
+
async disconnectWhatsApp() {
|
|
80
|
+
await this.request('/whatsapp/disconnect', { method: 'POST' });
|
|
81
|
+
}
|
|
82
|
+
/** Request a pairing code for phone-number-based linking. */
|
|
83
|
+
async pairByPhone(phoneNumber) {
|
|
84
|
+
return this.request('/whatsapp/pair-by-phone', {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
body: JSON.stringify({ phoneNumber }),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Poll for WhatsApp connection, resolving when connected.
|
|
91
|
+
*
|
|
92
|
+
* @param intervalMs - Polling interval in milliseconds (default: 3000)
|
|
93
|
+
* @param timeoutMs - Maximum wait time in milliseconds (default: 120000)
|
|
94
|
+
* @param onQr - Optional callback invoked each time a new QR is available
|
|
95
|
+
* @returns The final WhatsApp status (connected)
|
|
96
|
+
*/
|
|
97
|
+
async waitForConnection(options) {
|
|
98
|
+
const interval = options?.intervalMs ?? 3000;
|
|
99
|
+
const timeout = options?.timeoutMs ?? 120_000;
|
|
100
|
+
const start = Date.now();
|
|
101
|
+
let lastQr = '';
|
|
102
|
+
while (Date.now() - start < timeout) {
|
|
103
|
+
const status = await this.getWhatsAppStatus();
|
|
104
|
+
if (status.connected || status.state === 'connected') {
|
|
105
|
+
return status;
|
|
106
|
+
}
|
|
107
|
+
if (status.qr && status.qr !== lastQr && options?.onQr) {
|
|
108
|
+
lastQr = status.qr;
|
|
109
|
+
options.onQr(status.qr);
|
|
110
|
+
}
|
|
111
|
+
await new Promise(r => setTimeout(r, interval));
|
|
112
|
+
}
|
|
113
|
+
throw new OrqoError('Connection timeout — QR was not scanned in time', 408);
|
|
114
|
+
}
|
|
115
|
+
// --------------------------------------------------------------------------
|
|
116
|
+
// Messaging
|
|
117
|
+
// --------------------------------------------------------------------------
|
|
118
|
+
/** Send a text message via WhatsApp. */
|
|
119
|
+
async sendMessage(options) {
|
|
120
|
+
return this.request('/messages/send', {
|
|
121
|
+
method: 'POST',
|
|
122
|
+
body: JSON.stringify(options),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// --------------------------------------------------------------------------
|
|
126
|
+
// Agent CRUD
|
|
127
|
+
// --------------------------------------------------------------------------
|
|
128
|
+
/** Create a new agent for this instance. */
|
|
129
|
+
async createAgent(config) {
|
|
130
|
+
return this.request('/agents', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
body: JSON.stringify(config),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/** List all agents. */
|
|
136
|
+
async listAgents() {
|
|
137
|
+
return this.request('/agents');
|
|
138
|
+
}
|
|
139
|
+
/** Update an existing agent. */
|
|
140
|
+
async updateAgent(agentId, updates) {
|
|
141
|
+
return this.request(`/agents/${agentId}`, {
|
|
142
|
+
method: 'PATCH',
|
|
143
|
+
body: JSON.stringify(updates),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/** Delete an agent. */
|
|
147
|
+
async deleteAgent(agentId) {
|
|
148
|
+
await this.request(`/agents/${agentId}`, { method: 'DELETE' });
|
|
149
|
+
}
|
|
150
|
+
// --------------------------------------------------------------------------
|
|
151
|
+
// Webhook Management
|
|
152
|
+
// --------------------------------------------------------------------------
|
|
153
|
+
/** Register a webhook to receive events. */
|
|
154
|
+
async addWebhook(config) {
|
|
155
|
+
return this.request('/webhooks', {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
body: JSON.stringify(config),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/** List all registered webhooks. */
|
|
161
|
+
async listWebhooks() {
|
|
162
|
+
return this.request('/webhooks');
|
|
163
|
+
}
|
|
164
|
+
/** Remove a webhook. */
|
|
165
|
+
async removeWebhook(webhookId) {
|
|
166
|
+
await this.request(`/webhooks/${webhookId}`, { method: 'DELETE' });
|
|
167
|
+
}
|
|
168
|
+
// --------------------------------------------------------------------------
|
|
169
|
+
// Guardrails
|
|
170
|
+
// --------------------------------------------------------------------------
|
|
171
|
+
/** Set guardrail configuration for AI responses. */
|
|
172
|
+
async setGuardrails(config) {
|
|
173
|
+
return this.request('/guardrails', {
|
|
174
|
+
method: 'PUT',
|
|
175
|
+
body: JSON.stringify(config),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/** Get current guardrail configuration. */
|
|
179
|
+
async getGuardrails() {
|
|
180
|
+
return this.request('/guardrails');
|
|
181
|
+
}
|
|
182
|
+
// --------------------------------------------------------------------------
|
|
183
|
+
// Session / Handoff
|
|
184
|
+
// --------------------------------------------------------------------------
|
|
185
|
+
/** Hand off a conversation to a human agent. */
|
|
186
|
+
async handoffToHuman(options) {
|
|
187
|
+
return this.request(`/sessions/${options.sessionId}/handoff`, {
|
|
188
|
+
method: 'POST',
|
|
189
|
+
body: JSON.stringify({
|
|
190
|
+
reason: options.reason,
|
|
191
|
+
target: options.target,
|
|
192
|
+
metadata: options.metadata,
|
|
193
|
+
}),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Resume bot control of a conversation after human handoff. */
|
|
197
|
+
async resumeBot(sessionId) {
|
|
198
|
+
return this.request(`/sessions/${sessionId}/resume`, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// --------------------------------------------------------------------------
|
|
203
|
+
// Stats & Messages
|
|
204
|
+
// --------------------------------------------------------------------------
|
|
205
|
+
/** Get instance statistics (messages, sessions, uptime). */
|
|
206
|
+
async getStats() {
|
|
207
|
+
return this.request('/stats');
|
|
208
|
+
}
|
|
209
|
+
/** Get conversation sessions with pagination. */
|
|
210
|
+
async getSessions(options) {
|
|
211
|
+
const params = new URLSearchParams();
|
|
212
|
+
if (options?.limit)
|
|
213
|
+
params.set('limit', String(options.limit));
|
|
214
|
+
if (options?.offset)
|
|
215
|
+
params.set('offset', String(options.offset));
|
|
216
|
+
const qs = params.toString();
|
|
217
|
+
return this.request(`/messages/sessions${qs ? `?${qs}` : ''}`);
|
|
218
|
+
}
|
|
219
|
+
/** Get messages for a session or all messages. */
|
|
220
|
+
async getMessages(options) {
|
|
221
|
+
const params = new URLSearchParams();
|
|
222
|
+
if (options?.sessionKey)
|
|
223
|
+
params.set('sessionKey', options.sessionKey);
|
|
224
|
+
if (options?.limit)
|
|
225
|
+
params.set('limit', String(options.limit));
|
|
226
|
+
const qs = params.toString();
|
|
227
|
+
return this.request(`/messages${qs ? `?${qs}` : ''}`);
|
|
228
|
+
}
|
|
229
|
+
// --------------------------------------------------------------------------
|
|
230
|
+
// WhatsApp — Extended
|
|
231
|
+
// --------------------------------------------------------------------------
|
|
232
|
+
/** Force reconnect WhatsApp (useful for stale connections). */
|
|
233
|
+
async reconnectWhatsApp() {
|
|
234
|
+
return this.request('/whatsapp/reconnect', { method: 'POST' });
|
|
235
|
+
}
|
|
236
|
+
// --------------------------------------------------------------------------
|
|
237
|
+
// Agent — Extended
|
|
238
|
+
// --------------------------------------------------------------------------
|
|
239
|
+
/** Get a specific agent by ID. */
|
|
240
|
+
async getAgent(agentId) {
|
|
241
|
+
return this.request(`/agents/${agentId}`);
|
|
242
|
+
}
|
|
243
|
+
// --------------------------------------------------------------------------
|
|
244
|
+
// Cron Jobs
|
|
245
|
+
// --------------------------------------------------------------------------
|
|
246
|
+
/** List cron jobs for this instance. */
|
|
247
|
+
async listCronJobs() {
|
|
248
|
+
return this.request('/cron');
|
|
249
|
+
}
|
|
250
|
+
/** Create a new cron job. */
|
|
251
|
+
async createCronJob(config) {
|
|
252
|
+
return this.request('/cron', {
|
|
253
|
+
method: 'POST',
|
|
254
|
+
body: JSON.stringify(config),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** Delete a cron job. */
|
|
258
|
+
async deleteCronJob(jobId) {
|
|
259
|
+
await this.request(`/cron/${jobId}`, { method: 'DELETE' });
|
|
260
|
+
}
|
|
261
|
+
/** Manually trigger a cron job. */
|
|
262
|
+
async runCronJob(jobId) {
|
|
263
|
+
return this.request(`/cron/${jobId}/run`, { method: 'POST' });
|
|
264
|
+
}
|
|
265
|
+
// --------------------------------------------------------------------------
|
|
266
|
+
// API Bridge (Dynamic Tool Integration)
|
|
267
|
+
// --------------------------------------------------------------------------
|
|
268
|
+
/**
|
|
269
|
+
* Connect an external API via OpenAPI spec.
|
|
270
|
+
* The agent will automatically gain tools from the spec.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* await instance.connectApi({
|
|
275
|
+
* name: 'comanda-api',
|
|
276
|
+
* specUrl: 'https://api.comanda.app/openapi.json',
|
|
277
|
+
* auth: { type: 'bearer', token: 'client-key' },
|
|
278
|
+
* });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
async connectApi(options) {
|
|
282
|
+
return this.request('/api-bridge', {
|
|
283
|
+
method: 'POST',
|
|
284
|
+
body: JSON.stringify(options),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/** List all connected API Bridges. */
|
|
288
|
+
async listApiBridges() {
|
|
289
|
+
return this.request('/api-bridge');
|
|
290
|
+
}
|
|
291
|
+
/** Remove an API Bridge by ID. */
|
|
292
|
+
async removeApiBridge(bridgeId) {
|
|
293
|
+
return this.request(`/api-bridge/${bridgeId}`, { method: 'DELETE' });
|
|
294
|
+
}
|
|
295
|
+
/** Refresh an API Bridge (re-fetch OpenAPI spec and update tools). */
|
|
296
|
+
async refreshApiBridge(bridgeId) {
|
|
297
|
+
return this.request(`/api-bridge/${bridgeId}/refresh`, { method: 'POST' });
|
|
298
|
+
}
|
|
299
|
+
// --------------------------------------------------------------------------
|
|
300
|
+
// Webhook — Extended
|
|
301
|
+
// --------------------------------------------------------------------------
|
|
302
|
+
/** Update an existing webhook configuration. */
|
|
303
|
+
async updateWebhook(webhookId, updates) {
|
|
304
|
+
return this.request(`/webhooks/${webhookId}`, {
|
|
305
|
+
method: 'PATCH',
|
|
306
|
+
body: JSON.stringify(updates),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/** Send a test event to a webhook endpoint. */
|
|
310
|
+
async testWebhook(webhookId) {
|
|
311
|
+
return this.request(`/webhooks/${webhookId}/test`, { method: 'POST' });
|
|
312
|
+
}
|
|
313
|
+
// --------------------------------------------------------------------------
|
|
314
|
+
// Cron Jobs — Extended
|
|
315
|
+
// --------------------------------------------------------------------------
|
|
316
|
+
/** Update an existing cron job. */
|
|
317
|
+
async updateCronJob(jobId, updates) {
|
|
318
|
+
return this.request(`/cron/${jobId}`, {
|
|
319
|
+
method: 'PATCH',
|
|
320
|
+
body: JSON.stringify(updates),
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
// --------------------------------------------------------------------------
|
|
324
|
+
// Monitoring — Extended
|
|
325
|
+
// --------------------------------------------------------------------------
|
|
326
|
+
/** Get resource limits and current usage. */
|
|
327
|
+
async getLimits() {
|
|
328
|
+
return this.request('/limits');
|
|
329
|
+
}
|
|
330
|
+
// --------------------------------------------------------------------------
|
|
331
|
+
// Backup
|
|
332
|
+
// --------------------------------------------------------------------------
|
|
333
|
+
/** Create a backup of this instance. */
|
|
334
|
+
async backup() {
|
|
335
|
+
return this.request('/backup', { method: 'POST' });
|
|
336
|
+
}
|
|
337
|
+
// --------------------------------------------------------------------------
|
|
338
|
+
// AI Agent Generation
|
|
339
|
+
// --------------------------------------------------------------------------
|
|
340
|
+
/** Generate an agent configuration using AI. */
|
|
341
|
+
async generateAgent(config) {
|
|
342
|
+
return this.request('/agents/ai/generate', {
|
|
343
|
+
method: 'POST',
|
|
344
|
+
body: JSON.stringify(config),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
// --------------------------------------------------------------------------
|
|
348
|
+
// Background Jobs
|
|
349
|
+
// --------------------------------------------------------------------------
|
|
350
|
+
/** List all background jobs for this instance. */
|
|
351
|
+
async listBackgroundJobs() {
|
|
352
|
+
return this.request('/background');
|
|
353
|
+
}
|
|
354
|
+
/** Get a specific background job by ID. */
|
|
355
|
+
async getBackgroundJob(jobId) {
|
|
356
|
+
return this.request(`/background/${jobId}`);
|
|
357
|
+
}
|
|
358
|
+
/** Create a new background job. */
|
|
359
|
+
async createBackgroundJob(config) {
|
|
360
|
+
return this.request('/background', {
|
|
361
|
+
method: 'POST',
|
|
362
|
+
body: JSON.stringify(config),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orqo Gateway SDK — Types
|
|
3
|
+
*
|
|
4
|
+
* Zero-dependency type definitions for the Orqo REST API.
|
|
5
|
+
*/
|
|
6
|
+
export interface OrqoClientConfig {
|
|
7
|
+
/** Base URL of the Orqo Gateway (e.g. "https://orqo.example.com") */
|
|
8
|
+
host: string;
|
|
9
|
+
/** Admin token for /api/admin/* endpoints */
|
|
10
|
+
adminToken: string;
|
|
11
|
+
/** Optional fetch implementation (defaults to globalThis.fetch) */
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
/** Retry configuration for resilience */
|
|
14
|
+
retry?: RetryConfig;
|
|
15
|
+
}
|
|
16
|
+
export interface RetryConfig {
|
|
17
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
18
|
+
maxAttempts?: number;
|
|
19
|
+
/** Initial backoff in ms (default: 1000) */
|
|
20
|
+
backoffMs?: number;
|
|
21
|
+
/** Backoff multiplier (default: 2) */
|
|
22
|
+
multiplier?: number;
|
|
23
|
+
/** HTTP status codes to retry on (default: [429, 500, 502, 503, 504]) */
|
|
24
|
+
retryOn?: number[];
|
|
25
|
+
}
|
|
26
|
+
export interface OrqoInstanceConfig {
|
|
27
|
+
/** Base URL of the Orqo Gateway */
|
|
28
|
+
host: string;
|
|
29
|
+
/** Instance ID */
|
|
30
|
+
instanceId: string;
|
|
31
|
+
/** Instance API token */
|
|
32
|
+
apiToken: string;
|
|
33
|
+
/** Optional fetch implementation */
|
|
34
|
+
fetch?: typeof fetch;
|
|
35
|
+
/** Retry configuration */
|
|
36
|
+
retry?: RetryConfig;
|
|
37
|
+
}
|
|
38
|
+
export interface ProvisionOptions {
|
|
39
|
+
/** Display name for the instance */
|
|
40
|
+
name: string;
|
|
41
|
+
/** Optional description */
|
|
42
|
+
description?: string;
|
|
43
|
+
/** Webhook URL to receive events (connection changes, messages) */
|
|
44
|
+
webhookUrl?: string;
|
|
45
|
+
/** HMAC secret for webhook signature verification */
|
|
46
|
+
webhookSecret?: string;
|
|
47
|
+
/** Additional instance configuration */
|
|
48
|
+
config?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
export interface ProvisionResult {
|
|
51
|
+
instanceId: string;
|
|
52
|
+
apiToken: string;
|
|
53
|
+
whatsapp: WhatsAppStatus;
|
|
54
|
+
}
|
|
55
|
+
export interface WhatsAppStatus {
|
|
56
|
+
state: 'initializing' | 'waiting-qr' | 'connected' | 'disconnected';
|
|
57
|
+
qr: string | null;
|
|
58
|
+
qrRaw: string | null;
|
|
59
|
+
connected?: boolean;
|
|
60
|
+
phoneNumber?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface SendMessageOptions {
|
|
63
|
+
/** Destination JID (e.g. "5511999887766@s.whatsapp.net") */
|
|
64
|
+
to: string;
|
|
65
|
+
/** Text content */
|
|
66
|
+
text: string;
|
|
67
|
+
}
|
|
68
|
+
export interface SendMessageResult {
|
|
69
|
+
messageId?: string;
|
|
70
|
+
status: string;
|
|
71
|
+
}
|
|
72
|
+
export interface InstanceStatus {
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
connected: boolean;
|
|
76
|
+
whatsappState?: string;
|
|
77
|
+
uptime?: number;
|
|
78
|
+
channels?: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
export interface AgentConfig {
|
|
81
|
+
/** Agent ID (auto-generated if not provided) */
|
|
82
|
+
id?: string;
|
|
83
|
+
/** Human-readable agent name */
|
|
84
|
+
name: string;
|
|
85
|
+
/** Agent type */
|
|
86
|
+
type?: 'chat' | 'router' | 'specialist';
|
|
87
|
+
/** System prompt / instructions for the LLM */
|
|
88
|
+
systemPrompt?: string;
|
|
89
|
+
/** List of tool names the agent can use */
|
|
90
|
+
tools?: string[];
|
|
91
|
+
/** Agent identity */
|
|
92
|
+
identity?: {
|
|
93
|
+
displayName?: string;
|
|
94
|
+
emoji?: string;
|
|
95
|
+
};
|
|
96
|
+
/** Routing rules for multi-agent setups */
|
|
97
|
+
routingRules?: Record<string, unknown>;
|
|
98
|
+
/** Additional configuration */
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
export interface Agent extends AgentConfig {
|
|
102
|
+
id: string;
|
|
103
|
+
createdAt?: number;
|
|
104
|
+
}
|
|
105
|
+
export interface WebhookConfig {
|
|
106
|
+
/** Destination URL for webhook delivery */
|
|
107
|
+
url: string;
|
|
108
|
+
/** HMAC secret for signature verification */
|
|
109
|
+
secret?: string;
|
|
110
|
+
/** Event type to listen for */
|
|
111
|
+
event: string;
|
|
112
|
+
}
|
|
113
|
+
export interface Webhook extends WebhookConfig {
|
|
114
|
+
id: string;
|
|
115
|
+
}
|
|
116
|
+
export interface GuardrailConfig {
|
|
117
|
+
/** Content filtering rules */
|
|
118
|
+
blockedTopics?: string[];
|
|
119
|
+
/** Maximum response length */
|
|
120
|
+
maxResponseLength?: number;
|
|
121
|
+
/** Whether to filter PII from responses */
|
|
122
|
+
filterPII?: boolean;
|
|
123
|
+
/** Custom rules */
|
|
124
|
+
customRules?: Array<{
|
|
125
|
+
name: string;
|
|
126
|
+
pattern: string;
|
|
127
|
+
action: 'block' | 'warn' | 'redact';
|
|
128
|
+
}>;
|
|
129
|
+
/** Additional guardrail settings */
|
|
130
|
+
[key: string]: unknown;
|
|
131
|
+
}
|
|
132
|
+
export interface HandoffOptions {
|
|
133
|
+
/** Session/conversation ID */
|
|
134
|
+
sessionId: string;
|
|
135
|
+
/** Reason for handoff */
|
|
136
|
+
reason?: string;
|
|
137
|
+
/** Target human agent/queue */
|
|
138
|
+
target?: string;
|
|
139
|
+
/** Metadata to pass to human agent */
|
|
140
|
+
metadata?: Record<string, unknown>;
|
|
141
|
+
}
|
|
142
|
+
export interface HandoffResult {
|
|
143
|
+
success: boolean;
|
|
144
|
+
sessionId: string;
|
|
145
|
+
status: string;
|
|
146
|
+
}
|
|
147
|
+
export interface WebhookEvent {
|
|
148
|
+
event: string;
|
|
149
|
+
instanceId: string;
|
|
150
|
+
timestamp: number;
|
|
151
|
+
}
|
|
152
|
+
export interface ConnectionChangedEvent extends WebhookEvent {
|
|
153
|
+
event: 'connection:changed';
|
|
154
|
+
state: 'connected' | 'disconnected';
|
|
155
|
+
phoneNumber: string | null;
|
|
156
|
+
}
|
|
157
|
+
export interface MessageReceivedEvent extends WebhookEvent {
|
|
158
|
+
event: 'message:received';
|
|
159
|
+
from: string;
|
|
160
|
+
text: string;
|
|
161
|
+
messageId: string;
|
|
162
|
+
isGroup: boolean;
|
|
163
|
+
pushName?: string;
|
|
164
|
+
}
|
|
165
|
+
export interface MessageProcessedEvent extends WebhookEvent {
|
|
166
|
+
event: 'message:processed';
|
|
167
|
+
messageId: string;
|
|
168
|
+
agentId?: string;
|
|
169
|
+
response?: string;
|
|
170
|
+
}
|
|
171
|
+
export interface HandoffEvent extends WebhookEvent {
|
|
172
|
+
event: 'session:handoff';
|
|
173
|
+
sessionId: string;
|
|
174
|
+
reason?: string;
|
|
175
|
+
from: string;
|
|
176
|
+
}
|
|
177
|
+
/** Union of all known webhook events */
|
|
178
|
+
export type OrqoWebhookEvent = ConnectionChangedEvent | MessageReceivedEvent | MessageProcessedEvent | HandoffEvent | WebhookEvent;
|
|
179
|
+
export interface WebhookHandlerOptions {
|
|
180
|
+
/** HMAC secret for signature verification */
|
|
181
|
+
secret?: string;
|
|
182
|
+
/** Called when WhatsApp connection state changes */
|
|
183
|
+
onConnectionChanged?: (event: ConnectionChangedEvent) => void | Promise<void>;
|
|
184
|
+
/** Called when a new message is received */
|
|
185
|
+
onMessageReceived?: (event: MessageReceivedEvent) => void | Promise<void>;
|
|
186
|
+
/** Called when a message has been processed by the AI */
|
|
187
|
+
onMessageProcessed?: (event: MessageProcessedEvent) => void | Promise<void>;
|
|
188
|
+
/** Called when a session is handed off to a human */
|
|
189
|
+
onHandoff?: (event: HandoffEvent) => void | Promise<void>;
|
|
190
|
+
/** Catch-all for any event */
|
|
191
|
+
onEvent?: (event: OrqoWebhookEvent) => void | Promise<void>;
|
|
192
|
+
/** Called on signature verification failure */
|
|
193
|
+
onVerificationFailed?: (error: Error) => void;
|
|
194
|
+
}
|
|
195
|
+
export declare class OrqoError extends Error {
|
|
196
|
+
readonly status: number;
|
|
197
|
+
readonly body?: unknown | undefined;
|
|
198
|
+
constructor(message: string, status: number, body?: unknown | undefined);
|
|
199
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orqo Gateway SDK — Types
|
|
3
|
+
*
|
|
4
|
+
* Zero-dependency type definitions for the Orqo REST API.
|
|
5
|
+
*/
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Errors
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export class OrqoError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
body;
|
|
12
|
+
constructor(message, status, body) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.body = body;
|
|
16
|
+
this.name = 'OrqoError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook Handler — Zero-dependency event dispatcher
|
|
3
|
+
*
|
|
4
|
+
* Creates a request handler that verifies HMAC signatures
|
|
5
|
+
* and dispatches typed events to registered callbacks.
|
|
6
|
+
*
|
|
7
|
+
* Works with any HTTP framework (Express, Hono, Fastify, etc.)
|
|
8
|
+
* via a generic interface.
|
|
9
|
+
*
|
|
10
|
+
* @example Express
|
|
11
|
+
* ```ts
|
|
12
|
+
* import express from 'express';
|
|
13
|
+
* import { createWebhookHandler } from '@orqo/sdk';
|
|
14
|
+
*
|
|
15
|
+
* const app = express();
|
|
16
|
+
* app.use(express.json());
|
|
17
|
+
*
|
|
18
|
+
* app.post('/webhooks/orqo', createWebhookHandler({
|
|
19
|
+
* secret: 'my-hmac-secret',
|
|
20
|
+
* onConnectionChanged: (e) => console.log(`${e.instanceId} → ${e.state}`),
|
|
21
|
+
* onMessageReceived: (e) => console.log(`From ${e.from}: ${e.text}`),
|
|
22
|
+
* onMessageProcessed: (e) => console.log(`Processed: ${e.messageId}`),
|
|
23
|
+
* onHandoff: (e) => console.log(`Handoff: ${e.sessionId}`),
|
|
24
|
+
* }));
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import type { WebhookHandlerOptions } from './types.js';
|
|
28
|
+
/**
|
|
29
|
+
* Generic HTTP request/response interface.
|
|
30
|
+
* Compatible with Express, Hono, Node http, etc.
|
|
31
|
+
*/
|
|
32
|
+
interface GenericRequest {
|
|
33
|
+
body?: unknown;
|
|
34
|
+
headers?: Record<string, string | string[] | undefined> | {
|
|
35
|
+
get?: (name: string) => string | null;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
interface GenericResponse {
|
|
39
|
+
status?: (code: number) => GenericResponse;
|
|
40
|
+
json?: (data: unknown) => void;
|
|
41
|
+
writeHead?: (code: number, headers?: Record<string, string>) => void;
|
|
42
|
+
end?: (data?: string) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates a webhook handler function compatible with Express/Hono/etc.
|
|
46
|
+
*
|
|
47
|
+
* The handler:
|
|
48
|
+
* 1. Verifies the HMAC signature (if secret is configured)
|
|
49
|
+
* 2. Parses the event
|
|
50
|
+
* 3. Dispatches to the appropriate typed callback
|
|
51
|
+
* 4. Returns 200 OK
|
|
52
|
+
*/
|
|
53
|
+
export declare function createWebhookHandler(options: WebhookHandlerOptions): (req: GenericRequest, res: GenericResponse) => Promise<void>;
|
|
54
|
+
export {};
|