@graph8/sdk 0.3.0 → 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/dist/index.d.mts +624 -12
- package/dist/index.d.ts +624 -12
- package/dist/index.js +323 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +323 -8
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +622 -18
- package/dist/react.d.ts +622 -18
- package/dist/react.js +323 -8
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +323 -8
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -328,18 +328,133 @@ var DEFAULT_API7 = "https://be.graph8.com";
|
|
|
328
328
|
var createSequencesClient = (apiKey, apiUrl) => {
|
|
329
329
|
const baseUrl = apiUrl || DEFAULT_API7;
|
|
330
330
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
331
|
+
const toQuery = (params) => {
|
|
332
|
+
const qs = new URLSearchParams();
|
|
333
|
+
for (const [k, v] of Object.entries(params)) {
|
|
334
|
+
if (v != null) qs.set(k, String(v));
|
|
335
|
+
}
|
|
336
|
+
const s = qs.toString();
|
|
337
|
+
return s ? `?${s}` : "";
|
|
338
|
+
};
|
|
339
|
+
async function list(pageOrParams, limit) {
|
|
340
|
+
let params;
|
|
341
|
+
if (typeof pageOrParams === "number") {
|
|
342
|
+
params = { page: pageOrParams, limit: limit ?? 50 };
|
|
343
|
+
} else {
|
|
344
|
+
params = pageOrParams ?? {};
|
|
345
|
+
}
|
|
346
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences${toQuery(params)}`, { headers: headers() });
|
|
347
|
+
const data = await resp.json();
|
|
348
|
+
return data.data || data;
|
|
349
|
+
}
|
|
331
350
|
return {
|
|
332
|
-
|
|
333
|
-
|
|
351
|
+
/** List sequences with pagination + optional status filter. */
|
|
352
|
+
list,
|
|
353
|
+
/** Get full sequence details by ID. */
|
|
354
|
+
async get(sequenceId) {
|
|
355
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, { headers: headers() });
|
|
334
356
|
const data = await resp.json();
|
|
335
357
|
return data.data || data;
|
|
336
358
|
},
|
|
359
|
+
/** List contacts enrolled in a sequence. Filter by state (e.g. "active", "replied"). */
|
|
360
|
+
async contacts(sequenceId, params = {}) {
|
|
361
|
+
const resp = await fetch(
|
|
362
|
+
`${baseUrl}/api/v1/sequences/${sequenceId}/contacts${toQuery(params)}`,
|
|
363
|
+
{ headers: headers() }
|
|
364
|
+
);
|
|
365
|
+
return resp.json();
|
|
366
|
+
},
|
|
367
|
+
/** Add contacts to a sequence (V2 queuing). Live or drafted sequences only. */
|
|
337
368
|
async add(config) {
|
|
338
|
-
await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
369
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
339
370
|
method: "POST",
|
|
340
371
|
headers: headers(),
|
|
341
372
|
body: JSON.stringify({ contact_ids: config.contactIds, list_id: config.listId })
|
|
342
373
|
});
|
|
374
|
+
const data = await resp.json();
|
|
375
|
+
return data.data || data;
|
|
376
|
+
},
|
|
377
|
+
/** Create a new sequence with optional steps + channels. */
|
|
378
|
+
async create(payload) {
|
|
379
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences`, {
|
|
380
|
+
method: "POST",
|
|
381
|
+
headers: headers(),
|
|
382
|
+
body: JSON.stringify(payload)
|
|
383
|
+
});
|
|
384
|
+
const data = await resp.json();
|
|
385
|
+
return data.data || data;
|
|
386
|
+
},
|
|
387
|
+
/** Update sequence metadata. Rejected (409) if sequence is in a transitional status. */
|
|
388
|
+
async update(sequenceId, fields) {
|
|
389
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
390
|
+
method: "PATCH",
|
|
391
|
+
headers: headers(),
|
|
392
|
+
body: JSON.stringify(fields)
|
|
393
|
+
});
|
|
394
|
+
const data = await resp.json();
|
|
395
|
+
return data.data || data;
|
|
396
|
+
},
|
|
397
|
+
/** Update a single step within a sequence. */
|
|
398
|
+
async updateStep(sequenceId, stepId, fields) {
|
|
399
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/steps/${stepId}`, {
|
|
400
|
+
method: "PATCH",
|
|
401
|
+
headers: headers(),
|
|
402
|
+
body: JSON.stringify(fields)
|
|
403
|
+
});
|
|
404
|
+
const data = await resp.json();
|
|
405
|
+
return data.data || data;
|
|
406
|
+
},
|
|
407
|
+
/** Soft-delete (archive) a sequence. */
|
|
408
|
+
async delete(sequenceId) {
|
|
409
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
410
|
+
method: "DELETE",
|
|
411
|
+
headers: headers()
|
|
412
|
+
});
|
|
413
|
+
const data = await resp.json();
|
|
414
|
+
return data.data || data;
|
|
415
|
+
},
|
|
416
|
+
/** Run/start a DRAFTED sequence (V2 orchestration). */
|
|
417
|
+
async run(sequenceId) {
|
|
418
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/run`, {
|
|
419
|
+
method: "POST",
|
|
420
|
+
headers: headers()
|
|
421
|
+
});
|
|
422
|
+
const data = await resp.json();
|
|
423
|
+
return data.data || data;
|
|
424
|
+
},
|
|
425
|
+
/** Pause a live sequence. */
|
|
426
|
+
async pause(sequenceId) {
|
|
427
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/pause`, {
|
|
428
|
+
method: "POST",
|
|
429
|
+
headers: headers()
|
|
430
|
+
});
|
|
431
|
+
const data = await resp.json();
|
|
432
|
+
return data.data || data;
|
|
433
|
+
},
|
|
434
|
+
/** Resume a paused sequence. */
|
|
435
|
+
async resume(sequenceId) {
|
|
436
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/resume`, {
|
|
437
|
+
method: "POST",
|
|
438
|
+
headers: headers()
|
|
439
|
+
});
|
|
440
|
+
const data = await resp.json();
|
|
441
|
+
return data.data || data;
|
|
442
|
+
},
|
|
443
|
+
/** Read-only sequence preview with all steps + channels (no enrollment). */
|
|
444
|
+
async preview(sequenceId) {
|
|
445
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/preview`, {
|
|
446
|
+
headers: headers()
|
|
447
|
+
});
|
|
448
|
+
const data = await resp.json();
|
|
449
|
+
return data.data || data;
|
|
450
|
+
},
|
|
451
|
+
/** Comprehensive analytics for a sequence. */
|
|
452
|
+
async analytics(sequenceId) {
|
|
453
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/analytics`, {
|
|
454
|
+
headers: headers()
|
|
455
|
+
});
|
|
456
|
+
const data = await resp.json();
|
|
457
|
+
return data.data || data;
|
|
343
458
|
}
|
|
344
459
|
};
|
|
345
460
|
};
|
|
@@ -464,8 +579,116 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
464
579
|
const baseUrl = apiUrl || DEFAULT_API12;
|
|
465
580
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
466
581
|
const listeners = /* @__PURE__ */ new Map();
|
|
582
|
+
const toQuery = (params) => {
|
|
583
|
+
const qs = new URLSearchParams();
|
|
584
|
+
for (const [k, v] of Object.entries(params)) {
|
|
585
|
+
if (v != null) qs.set(k, String(v));
|
|
586
|
+
}
|
|
587
|
+
const s = qs.toString();
|
|
588
|
+
return s ? `?${s}` : "";
|
|
589
|
+
};
|
|
590
|
+
const dialer = {
|
|
591
|
+
/** List parallel-dialer sessions with filters + pagination. */
|
|
592
|
+
async listSessions(params = {}) {
|
|
593
|
+
const resp = await fetch(
|
|
594
|
+
`${baseUrl}/api/v1/voice/dialer/sessions${toQuery(params)}`,
|
|
595
|
+
{ headers: headers() }
|
|
596
|
+
);
|
|
597
|
+
const data = await resp.json();
|
|
598
|
+
return data.data || data;
|
|
599
|
+
},
|
|
600
|
+
/** Create a parallel-dialer session in PAUSED state. SDR opens UI to start dialing. */
|
|
601
|
+
async createSession(payload) {
|
|
602
|
+
const resp = await fetch(`${baseUrl}/api/v1/voice/dialer/sessions`, {
|
|
603
|
+
method: "POST",
|
|
604
|
+
headers: headers(),
|
|
605
|
+
body: JSON.stringify(payload)
|
|
606
|
+
});
|
|
607
|
+
const data = await resp.json();
|
|
608
|
+
return data.data || data;
|
|
609
|
+
},
|
|
610
|
+
/** Pause / resume / stop a dialer session via status flip. */
|
|
611
|
+
async updateSessionStatus(sessionId, status) {
|
|
612
|
+
const resp = await fetch(
|
|
613
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/status`,
|
|
614
|
+
{
|
|
615
|
+
method: "PATCH",
|
|
616
|
+
headers: headers(),
|
|
617
|
+
body: JSON.stringify({ status })
|
|
618
|
+
}
|
|
619
|
+
);
|
|
620
|
+
const data = await resp.json();
|
|
621
|
+
return data.data || data;
|
|
622
|
+
},
|
|
623
|
+
/**
|
|
624
|
+
* Resume a PAUSED dialer session. Auto-fetches the next batch from the source list,
|
|
625
|
+
* filters already-called + phoneless rows, and forwards to voice's start-session.
|
|
626
|
+
* @param maxContacts 1-4 (voice caps parallel dialing at 4). Default 4.
|
|
627
|
+
*/
|
|
628
|
+
async resumeSession(sessionId, maxContacts = 4) {
|
|
629
|
+
const resp = await fetch(
|
|
630
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/resume`,
|
|
631
|
+
{
|
|
632
|
+
method: "POST",
|
|
633
|
+
headers: headers(),
|
|
634
|
+
body: JSON.stringify({ max_contacts: maxContacts })
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
const data = await resp.json();
|
|
638
|
+
return data.data || data;
|
|
639
|
+
},
|
|
640
|
+
/** Aggregated dialer analytics (daily breakdown or total). */
|
|
641
|
+
async stats(params = {}) {
|
|
642
|
+
const resp = await fetch(
|
|
643
|
+
`${baseUrl}/api/v1/voice/dialer/stats${toQuery(params)}`,
|
|
644
|
+
{ headers: headers() }
|
|
645
|
+
);
|
|
646
|
+
const data = await resp.json();
|
|
647
|
+
return data.data || data;
|
|
648
|
+
},
|
|
649
|
+
/** List dialer-eligible phone numbers with 7-day stats + daily limits. */
|
|
650
|
+
async numbers(userEmail) {
|
|
651
|
+
const params = userEmail ? { user_email: userEmail } : {};
|
|
652
|
+
const resp = await fetch(
|
|
653
|
+
`${baseUrl}/api/v1/voice/dialer/numbers${toQuery(params)}`,
|
|
654
|
+
{ headers: headers() }
|
|
655
|
+
);
|
|
656
|
+
const data = await resp.json();
|
|
657
|
+
return data.data || data;
|
|
658
|
+
},
|
|
659
|
+
/** List missed inbound callbacks with caller / contact info. */
|
|
660
|
+
async missedCallbacks(limit = 50) {
|
|
661
|
+
const resp = await fetch(
|
|
662
|
+
`${baseUrl}/api/v1/voice/dialer/missed-callbacks${toQuery({ limit })}`,
|
|
663
|
+
{ headers: headers() }
|
|
664
|
+
);
|
|
665
|
+
const data = await resp.json();
|
|
666
|
+
return data.data || data;
|
|
667
|
+
},
|
|
668
|
+
/** AI grading for a single dialer call (returns "pending" while in progress). */
|
|
669
|
+
async callGrading(roomName) {
|
|
670
|
+
const resp = await fetch(
|
|
671
|
+
`${baseUrl}/api/v1/voice/dialer/calls/${encodeURIComponent(roomName)}/grading`,
|
|
672
|
+
{ headers: headers() }
|
|
673
|
+
);
|
|
674
|
+
const data = await resp.json();
|
|
675
|
+
return data.data || data;
|
|
676
|
+
},
|
|
677
|
+
/** List voice agents available for dialer sessions (capped at 100; no pagination). */
|
|
678
|
+
async agents(params = {}) {
|
|
679
|
+
const resp = await fetch(
|
|
680
|
+
`${baseUrl}/api/v1/voice/dialer/agents${toQuery(params)}`,
|
|
681
|
+
{ headers: headers() }
|
|
682
|
+
);
|
|
683
|
+
const data = await resp.json();
|
|
684
|
+
return data.data || data;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
467
687
|
return {
|
|
468
|
-
/**
|
|
688
|
+
/**
|
|
689
|
+
* Start an AI voice session.
|
|
690
|
+
* @deprecated Preview surface — for parallel-dialer flows use `voice.dialer.createSession()`.
|
|
691
|
+
*/
|
|
469
692
|
async start(config) {
|
|
470
693
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions`, {
|
|
471
694
|
method: "POST",
|
|
@@ -475,7 +698,10 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
475
698
|
const data = await resp.json();
|
|
476
699
|
return data.data || data;
|
|
477
700
|
},
|
|
478
|
-
/**
|
|
701
|
+
/**
|
|
702
|
+
* Get call analysis for a completed session.
|
|
703
|
+
* @deprecated Preview surface — for dialer-call grading use `voice.dialer.callGrading(roomName)`.
|
|
704
|
+
*/
|
|
479
705
|
async analysis(sessionId) {
|
|
480
706
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions/${sessionId}/analysis`, { headers: headers() });
|
|
481
707
|
const data = await resp.json();
|
|
@@ -485,7 +711,9 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
485
711
|
on(event, callback) {
|
|
486
712
|
if (!listeners.has(event)) listeners.set(event, []);
|
|
487
713
|
listeners.get(event).push(callback);
|
|
488
|
-
}
|
|
714
|
+
},
|
|
715
|
+
/** Parallel-dialer session control + analytics. */
|
|
716
|
+
dialer
|
|
489
717
|
};
|
|
490
718
|
};
|
|
491
719
|
|
|
@@ -1014,9 +1242,88 @@ var createDealsClient = (apiKey, apiUrl) => {
|
|
|
1014
1242
|
};
|
|
1015
1243
|
};
|
|
1016
1244
|
|
|
1245
|
+
// src/inbox.ts
|
|
1246
|
+
var DEFAULT_API22 = "https://be.graph8.com";
|
|
1247
|
+
var createInboxClient = (apiKey, apiUrl) => {
|
|
1248
|
+
const baseUrl = apiUrl || DEFAULT_API22;
|
|
1249
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1250
|
+
const toQuery = (params) => {
|
|
1251
|
+
const qs = new URLSearchParams();
|
|
1252
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1253
|
+
if (v != null) qs.set(k, String(v));
|
|
1254
|
+
}
|
|
1255
|
+
const s = qs.toString();
|
|
1256
|
+
return s ? `?${s}` : "";
|
|
1257
|
+
};
|
|
1258
|
+
return {
|
|
1259
|
+
/** List inbox threads across email, SMS, and LinkedIn. */
|
|
1260
|
+
async list(params = {}) {
|
|
1261
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox${toQuery(params)}`, { headers: headers() });
|
|
1262
|
+
return resp.json();
|
|
1263
|
+
},
|
|
1264
|
+
/** Get a single inbox thread. Defaults to email channel. */
|
|
1265
|
+
async get(replyId, channel = "email") {
|
|
1266
|
+
const resp = await fetch(
|
|
1267
|
+
`${baseUrl}/api/v1/inbox/${replyId}${toQuery({ channel })}`,
|
|
1268
|
+
{ headers: headers() }
|
|
1269
|
+
);
|
|
1270
|
+
const data = await resp.json();
|
|
1271
|
+
return data.data || data;
|
|
1272
|
+
},
|
|
1273
|
+
/** Assign a user to an inbox thread. */
|
|
1274
|
+
async assign(replyId, assigneeEmail, channel = "email") {
|
|
1275
|
+
const resp = await fetch(
|
|
1276
|
+
`${baseUrl}/api/v1/inbox/${replyId}/assign${toQuery({ channel })}`,
|
|
1277
|
+
{
|
|
1278
|
+
method: "POST",
|
|
1279
|
+
headers: headers(),
|
|
1280
|
+
body: JSON.stringify({ assignee_email: assigneeEmail })
|
|
1281
|
+
}
|
|
1282
|
+
);
|
|
1283
|
+
const data = await resp.json();
|
|
1284
|
+
return data.data || data;
|
|
1285
|
+
},
|
|
1286
|
+
/** Attach tag IDs to an inbox thread. */
|
|
1287
|
+
async tag(replyId, tagIds, channel = "email") {
|
|
1288
|
+
const resp = await fetch(
|
|
1289
|
+
`${baseUrl}/api/v1/inbox/${replyId}/tag${toQuery({ channel })}`,
|
|
1290
|
+
{
|
|
1291
|
+
method: "POST",
|
|
1292
|
+
headers: headers(),
|
|
1293
|
+
body: JSON.stringify({ tag_ids: tagIds })
|
|
1294
|
+
}
|
|
1295
|
+
);
|
|
1296
|
+
const data = await resp.json();
|
|
1297
|
+
return data.data || data;
|
|
1298
|
+
},
|
|
1299
|
+
/**
|
|
1300
|
+
* Generate an AI draft reply for a thread.
|
|
1301
|
+
* Charges credits — server returns 402 if balance is insufficient.
|
|
1302
|
+
*/
|
|
1303
|
+
async draft(replyId, channel = "email") {
|
|
1304
|
+
const resp = await fetch(
|
|
1305
|
+
`${baseUrl}/api/v1/inbox/${replyId}/draft${toQuery({ channel })}`,
|
|
1306
|
+
{ headers: headers() }
|
|
1307
|
+
);
|
|
1308
|
+
const data = await resp.json();
|
|
1309
|
+
return data.data || data;
|
|
1310
|
+
},
|
|
1311
|
+
/** Send a reply through email, SMS, or LinkedIn. */
|
|
1312
|
+
async send(replyId, payload) {
|
|
1313
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox/${replyId}/send`, {
|
|
1314
|
+
method: "POST",
|
|
1315
|
+
headers: headers(),
|
|
1316
|
+
body: JSON.stringify(payload)
|
|
1317
|
+
});
|
|
1318
|
+
const data = await resp.json();
|
|
1319
|
+
return data.data || data;
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1017
1324
|
// src/core.ts
|
|
1018
1325
|
var DEFAULT_HOST = "https://t.graph8.com";
|
|
1019
|
-
var
|
|
1326
|
+
var DEFAULT_API23 = "https://be.graph8.com";
|
|
1020
1327
|
var G8 = class {
|
|
1021
1328
|
constructor() {
|
|
1022
1329
|
/** @internal */
|
|
@@ -1065,6 +1372,8 @@ var G8 = class {
|
|
|
1065
1372
|
this._fields = null;
|
|
1066
1373
|
/** @internal */
|
|
1067
1374
|
this._deals = null;
|
|
1375
|
+
/** @internal */
|
|
1376
|
+
this._inbox = null;
|
|
1068
1377
|
}
|
|
1069
1378
|
/**
|
|
1070
1379
|
* Initialize the graph8 SDK. Must be called before any other method.
|
|
@@ -1079,7 +1388,7 @@ var G8 = class {
|
|
|
1079
1388
|
debug: config.debug
|
|
1080
1389
|
});
|
|
1081
1390
|
}
|
|
1082
|
-
const apiUrl = config.apiUrl ||
|
|
1391
|
+
const apiUrl = config.apiUrl || DEFAULT_API23;
|
|
1083
1392
|
const writeKey = config.writeKey || "";
|
|
1084
1393
|
const apiKey = config.apiKey || "";
|
|
1085
1394
|
if (writeKey) {
|
|
@@ -1106,6 +1415,7 @@ var G8 = class {
|
|
|
1106
1415
|
this._tasks = createTasksClient(apiKey, apiUrl);
|
|
1107
1416
|
this._fields = createFieldsClient(apiKey, apiUrl);
|
|
1108
1417
|
this._deals = createDealsClient(apiKey, apiUrl);
|
|
1418
|
+
this._inbox = createInboxClient(apiKey, apiUrl);
|
|
1109
1419
|
this._signals = createSignalsClient(apiKey, true, apiUrl);
|
|
1110
1420
|
}
|
|
1111
1421
|
}
|
|
@@ -1232,6 +1542,11 @@ var G8 = class {
|
|
|
1232
1542
|
this._assertKey("deals");
|
|
1233
1543
|
return this._deals;
|
|
1234
1544
|
}
|
|
1545
|
+
/** Multi-channel inbox — read + reply across email, SMS, LinkedIn (requires API key). */
|
|
1546
|
+
get inbox() {
|
|
1547
|
+
this._assertKey("inbox");
|
|
1548
|
+
return this._inbox;
|
|
1549
|
+
}
|
|
1235
1550
|
/** Whether the SDK has been initialized. */
|
|
1236
1551
|
get initialized() {
|
|
1237
1552
|
return this.config !== null;
|