@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/index.js
CHANGED
|
@@ -349,18 +349,133 @@ var DEFAULT_API7 = "https://be.graph8.com";
|
|
|
349
349
|
var createSequencesClient = (apiKey, apiUrl) => {
|
|
350
350
|
const baseUrl = apiUrl || DEFAULT_API7;
|
|
351
351
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
352
|
+
const toQuery = (params) => {
|
|
353
|
+
const qs = new URLSearchParams();
|
|
354
|
+
for (const [k, v] of Object.entries(params)) {
|
|
355
|
+
if (v != null) qs.set(k, String(v));
|
|
356
|
+
}
|
|
357
|
+
const s = qs.toString();
|
|
358
|
+
return s ? `?${s}` : "";
|
|
359
|
+
};
|
|
360
|
+
async function list(pageOrParams, limit) {
|
|
361
|
+
let params;
|
|
362
|
+
if (typeof pageOrParams === "number") {
|
|
363
|
+
params = { page: pageOrParams, limit: limit ?? 50 };
|
|
364
|
+
} else {
|
|
365
|
+
params = pageOrParams ?? {};
|
|
366
|
+
}
|
|
367
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences${toQuery(params)}`, { headers: headers() });
|
|
368
|
+
const data = await resp.json();
|
|
369
|
+
return data.data || data;
|
|
370
|
+
}
|
|
352
371
|
return {
|
|
353
|
-
|
|
354
|
-
|
|
372
|
+
/** List sequences with pagination + optional status filter. */
|
|
373
|
+
list,
|
|
374
|
+
/** Get full sequence details by ID. */
|
|
375
|
+
async get(sequenceId) {
|
|
376
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, { headers: headers() });
|
|
355
377
|
const data = await resp.json();
|
|
356
378
|
return data.data || data;
|
|
357
379
|
},
|
|
380
|
+
/** List contacts enrolled in a sequence. Filter by state (e.g. "active", "replied"). */
|
|
381
|
+
async contacts(sequenceId, params = {}) {
|
|
382
|
+
const resp = await fetch(
|
|
383
|
+
`${baseUrl}/api/v1/sequences/${sequenceId}/contacts${toQuery(params)}`,
|
|
384
|
+
{ headers: headers() }
|
|
385
|
+
);
|
|
386
|
+
return resp.json();
|
|
387
|
+
},
|
|
388
|
+
/** Add contacts to a sequence (V2 queuing). Live or drafted sequences only. */
|
|
358
389
|
async add(config) {
|
|
359
|
-
await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
390
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
360
391
|
method: "POST",
|
|
361
392
|
headers: headers(),
|
|
362
393
|
body: JSON.stringify({ contact_ids: config.contactIds, list_id: config.listId })
|
|
363
394
|
});
|
|
395
|
+
const data = await resp.json();
|
|
396
|
+
return data.data || data;
|
|
397
|
+
},
|
|
398
|
+
/** Create a new sequence with optional steps + channels. */
|
|
399
|
+
async create(payload) {
|
|
400
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences`, {
|
|
401
|
+
method: "POST",
|
|
402
|
+
headers: headers(),
|
|
403
|
+
body: JSON.stringify(payload)
|
|
404
|
+
});
|
|
405
|
+
const data = await resp.json();
|
|
406
|
+
return data.data || data;
|
|
407
|
+
},
|
|
408
|
+
/** Update sequence metadata. Rejected (409) if sequence is in a transitional status. */
|
|
409
|
+
async update(sequenceId, fields) {
|
|
410
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
411
|
+
method: "PATCH",
|
|
412
|
+
headers: headers(),
|
|
413
|
+
body: JSON.stringify(fields)
|
|
414
|
+
});
|
|
415
|
+
const data = await resp.json();
|
|
416
|
+
return data.data || data;
|
|
417
|
+
},
|
|
418
|
+
/** Update a single step within a sequence. */
|
|
419
|
+
async updateStep(sequenceId, stepId, fields) {
|
|
420
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/steps/${stepId}`, {
|
|
421
|
+
method: "PATCH",
|
|
422
|
+
headers: headers(),
|
|
423
|
+
body: JSON.stringify(fields)
|
|
424
|
+
});
|
|
425
|
+
const data = await resp.json();
|
|
426
|
+
return data.data || data;
|
|
427
|
+
},
|
|
428
|
+
/** Soft-delete (archive) a sequence. */
|
|
429
|
+
async delete(sequenceId) {
|
|
430
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
431
|
+
method: "DELETE",
|
|
432
|
+
headers: headers()
|
|
433
|
+
});
|
|
434
|
+
const data = await resp.json();
|
|
435
|
+
return data.data || data;
|
|
436
|
+
},
|
|
437
|
+
/** Run/start a DRAFTED sequence (V2 orchestration). */
|
|
438
|
+
async run(sequenceId) {
|
|
439
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/run`, {
|
|
440
|
+
method: "POST",
|
|
441
|
+
headers: headers()
|
|
442
|
+
});
|
|
443
|
+
const data = await resp.json();
|
|
444
|
+
return data.data || data;
|
|
445
|
+
},
|
|
446
|
+
/** Pause a live sequence. */
|
|
447
|
+
async pause(sequenceId) {
|
|
448
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/pause`, {
|
|
449
|
+
method: "POST",
|
|
450
|
+
headers: headers()
|
|
451
|
+
});
|
|
452
|
+
const data = await resp.json();
|
|
453
|
+
return data.data || data;
|
|
454
|
+
},
|
|
455
|
+
/** Resume a paused sequence. */
|
|
456
|
+
async resume(sequenceId) {
|
|
457
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/resume`, {
|
|
458
|
+
method: "POST",
|
|
459
|
+
headers: headers()
|
|
460
|
+
});
|
|
461
|
+
const data = await resp.json();
|
|
462
|
+
return data.data || data;
|
|
463
|
+
},
|
|
464
|
+
/** Read-only sequence preview with all steps + channels (no enrollment). */
|
|
465
|
+
async preview(sequenceId) {
|
|
466
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/preview`, {
|
|
467
|
+
headers: headers()
|
|
468
|
+
});
|
|
469
|
+
const data = await resp.json();
|
|
470
|
+
return data.data || data;
|
|
471
|
+
},
|
|
472
|
+
/** Comprehensive analytics for a sequence. */
|
|
473
|
+
async analytics(sequenceId) {
|
|
474
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/analytics`, {
|
|
475
|
+
headers: headers()
|
|
476
|
+
});
|
|
477
|
+
const data = await resp.json();
|
|
478
|
+
return data.data || data;
|
|
364
479
|
}
|
|
365
480
|
};
|
|
366
481
|
};
|
|
@@ -485,8 +600,116 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
485
600
|
const baseUrl = apiUrl || DEFAULT_API12;
|
|
486
601
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
487
602
|
const listeners = /* @__PURE__ */ new Map();
|
|
603
|
+
const toQuery = (params) => {
|
|
604
|
+
const qs = new URLSearchParams();
|
|
605
|
+
for (const [k, v] of Object.entries(params)) {
|
|
606
|
+
if (v != null) qs.set(k, String(v));
|
|
607
|
+
}
|
|
608
|
+
const s = qs.toString();
|
|
609
|
+
return s ? `?${s}` : "";
|
|
610
|
+
};
|
|
611
|
+
const dialer = {
|
|
612
|
+
/** List parallel-dialer sessions with filters + pagination. */
|
|
613
|
+
async listSessions(params = {}) {
|
|
614
|
+
const resp = await fetch(
|
|
615
|
+
`${baseUrl}/api/v1/voice/dialer/sessions${toQuery(params)}`,
|
|
616
|
+
{ headers: headers() }
|
|
617
|
+
);
|
|
618
|
+
const data = await resp.json();
|
|
619
|
+
return data.data || data;
|
|
620
|
+
},
|
|
621
|
+
/** Create a parallel-dialer session in PAUSED state. SDR opens UI to start dialing. */
|
|
622
|
+
async createSession(payload) {
|
|
623
|
+
const resp = await fetch(`${baseUrl}/api/v1/voice/dialer/sessions`, {
|
|
624
|
+
method: "POST",
|
|
625
|
+
headers: headers(),
|
|
626
|
+
body: JSON.stringify(payload)
|
|
627
|
+
});
|
|
628
|
+
const data = await resp.json();
|
|
629
|
+
return data.data || data;
|
|
630
|
+
},
|
|
631
|
+
/** Pause / resume / stop a dialer session via status flip. */
|
|
632
|
+
async updateSessionStatus(sessionId, status) {
|
|
633
|
+
const resp = await fetch(
|
|
634
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/status`,
|
|
635
|
+
{
|
|
636
|
+
method: "PATCH",
|
|
637
|
+
headers: headers(),
|
|
638
|
+
body: JSON.stringify({ status })
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
const data = await resp.json();
|
|
642
|
+
return data.data || data;
|
|
643
|
+
},
|
|
644
|
+
/**
|
|
645
|
+
* Resume a PAUSED dialer session. Auto-fetches the next batch from the source list,
|
|
646
|
+
* filters already-called + phoneless rows, and forwards to voice's start-session.
|
|
647
|
+
* @param maxContacts 1-4 (voice caps parallel dialing at 4). Default 4.
|
|
648
|
+
*/
|
|
649
|
+
async resumeSession(sessionId, maxContacts = 4) {
|
|
650
|
+
const resp = await fetch(
|
|
651
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/resume`,
|
|
652
|
+
{
|
|
653
|
+
method: "POST",
|
|
654
|
+
headers: headers(),
|
|
655
|
+
body: JSON.stringify({ max_contacts: maxContacts })
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
const data = await resp.json();
|
|
659
|
+
return data.data || data;
|
|
660
|
+
},
|
|
661
|
+
/** Aggregated dialer analytics (daily breakdown or total). */
|
|
662
|
+
async stats(params = {}) {
|
|
663
|
+
const resp = await fetch(
|
|
664
|
+
`${baseUrl}/api/v1/voice/dialer/stats${toQuery(params)}`,
|
|
665
|
+
{ headers: headers() }
|
|
666
|
+
);
|
|
667
|
+
const data = await resp.json();
|
|
668
|
+
return data.data || data;
|
|
669
|
+
},
|
|
670
|
+
/** List dialer-eligible phone numbers with 7-day stats + daily limits. */
|
|
671
|
+
async numbers(userEmail) {
|
|
672
|
+
const params = userEmail ? { user_email: userEmail } : {};
|
|
673
|
+
const resp = await fetch(
|
|
674
|
+
`${baseUrl}/api/v1/voice/dialer/numbers${toQuery(params)}`,
|
|
675
|
+
{ headers: headers() }
|
|
676
|
+
);
|
|
677
|
+
const data = await resp.json();
|
|
678
|
+
return data.data || data;
|
|
679
|
+
},
|
|
680
|
+
/** List missed inbound callbacks with caller / contact info. */
|
|
681
|
+
async missedCallbacks(limit = 50) {
|
|
682
|
+
const resp = await fetch(
|
|
683
|
+
`${baseUrl}/api/v1/voice/dialer/missed-callbacks${toQuery({ limit })}`,
|
|
684
|
+
{ headers: headers() }
|
|
685
|
+
);
|
|
686
|
+
const data = await resp.json();
|
|
687
|
+
return data.data || data;
|
|
688
|
+
},
|
|
689
|
+
/** AI grading for a single dialer call (returns "pending" while in progress). */
|
|
690
|
+
async callGrading(roomName) {
|
|
691
|
+
const resp = await fetch(
|
|
692
|
+
`${baseUrl}/api/v1/voice/dialer/calls/${encodeURIComponent(roomName)}/grading`,
|
|
693
|
+
{ headers: headers() }
|
|
694
|
+
);
|
|
695
|
+
const data = await resp.json();
|
|
696
|
+
return data.data || data;
|
|
697
|
+
},
|
|
698
|
+
/** List voice agents available for dialer sessions (capped at 100; no pagination). */
|
|
699
|
+
async agents(params = {}) {
|
|
700
|
+
const resp = await fetch(
|
|
701
|
+
`${baseUrl}/api/v1/voice/dialer/agents${toQuery(params)}`,
|
|
702
|
+
{ headers: headers() }
|
|
703
|
+
);
|
|
704
|
+
const data = await resp.json();
|
|
705
|
+
return data.data || data;
|
|
706
|
+
}
|
|
707
|
+
};
|
|
488
708
|
return {
|
|
489
|
-
/**
|
|
709
|
+
/**
|
|
710
|
+
* Start an AI voice session.
|
|
711
|
+
* @deprecated Preview surface — for parallel-dialer flows use `voice.dialer.createSession()`.
|
|
712
|
+
*/
|
|
490
713
|
async start(config) {
|
|
491
714
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions`, {
|
|
492
715
|
method: "POST",
|
|
@@ -496,7 +719,10 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
496
719
|
const data = await resp.json();
|
|
497
720
|
return data.data || data;
|
|
498
721
|
},
|
|
499
|
-
/**
|
|
722
|
+
/**
|
|
723
|
+
* Get call analysis for a completed session.
|
|
724
|
+
* @deprecated Preview surface — for dialer-call grading use `voice.dialer.callGrading(roomName)`.
|
|
725
|
+
*/
|
|
500
726
|
async analysis(sessionId) {
|
|
501
727
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions/${sessionId}/analysis`, { headers: headers() });
|
|
502
728
|
const data = await resp.json();
|
|
@@ -506,7 +732,9 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
506
732
|
on(event, callback) {
|
|
507
733
|
if (!listeners.has(event)) listeners.set(event, []);
|
|
508
734
|
listeners.get(event).push(callback);
|
|
509
|
-
}
|
|
735
|
+
},
|
|
736
|
+
/** Parallel-dialer session control + analytics. */
|
|
737
|
+
dialer
|
|
510
738
|
};
|
|
511
739
|
};
|
|
512
740
|
|
|
@@ -1035,9 +1263,88 @@ var createDealsClient = (apiKey, apiUrl) => {
|
|
|
1035
1263
|
};
|
|
1036
1264
|
};
|
|
1037
1265
|
|
|
1266
|
+
// src/inbox.ts
|
|
1267
|
+
var DEFAULT_API22 = "https://be.graph8.com";
|
|
1268
|
+
var createInboxClient = (apiKey, apiUrl) => {
|
|
1269
|
+
const baseUrl = apiUrl || DEFAULT_API22;
|
|
1270
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1271
|
+
const toQuery = (params) => {
|
|
1272
|
+
const qs = new URLSearchParams();
|
|
1273
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1274
|
+
if (v != null) qs.set(k, String(v));
|
|
1275
|
+
}
|
|
1276
|
+
const s = qs.toString();
|
|
1277
|
+
return s ? `?${s}` : "";
|
|
1278
|
+
};
|
|
1279
|
+
return {
|
|
1280
|
+
/** List inbox threads across email, SMS, and LinkedIn. */
|
|
1281
|
+
async list(params = {}) {
|
|
1282
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox${toQuery(params)}`, { headers: headers() });
|
|
1283
|
+
return resp.json();
|
|
1284
|
+
},
|
|
1285
|
+
/** Get a single inbox thread. Defaults to email channel. */
|
|
1286
|
+
async get(replyId, channel = "email") {
|
|
1287
|
+
const resp = await fetch(
|
|
1288
|
+
`${baseUrl}/api/v1/inbox/${replyId}${toQuery({ channel })}`,
|
|
1289
|
+
{ headers: headers() }
|
|
1290
|
+
);
|
|
1291
|
+
const data = await resp.json();
|
|
1292
|
+
return data.data || data;
|
|
1293
|
+
},
|
|
1294
|
+
/** Assign a user to an inbox thread. */
|
|
1295
|
+
async assign(replyId, assigneeEmail, channel = "email") {
|
|
1296
|
+
const resp = await fetch(
|
|
1297
|
+
`${baseUrl}/api/v1/inbox/${replyId}/assign${toQuery({ channel })}`,
|
|
1298
|
+
{
|
|
1299
|
+
method: "POST",
|
|
1300
|
+
headers: headers(),
|
|
1301
|
+
body: JSON.stringify({ assignee_email: assigneeEmail })
|
|
1302
|
+
}
|
|
1303
|
+
);
|
|
1304
|
+
const data = await resp.json();
|
|
1305
|
+
return data.data || data;
|
|
1306
|
+
},
|
|
1307
|
+
/** Attach tag IDs to an inbox thread. */
|
|
1308
|
+
async tag(replyId, tagIds, channel = "email") {
|
|
1309
|
+
const resp = await fetch(
|
|
1310
|
+
`${baseUrl}/api/v1/inbox/${replyId}/tag${toQuery({ channel })}`,
|
|
1311
|
+
{
|
|
1312
|
+
method: "POST",
|
|
1313
|
+
headers: headers(),
|
|
1314
|
+
body: JSON.stringify({ tag_ids: tagIds })
|
|
1315
|
+
}
|
|
1316
|
+
);
|
|
1317
|
+
const data = await resp.json();
|
|
1318
|
+
return data.data || data;
|
|
1319
|
+
},
|
|
1320
|
+
/**
|
|
1321
|
+
* Generate an AI draft reply for a thread.
|
|
1322
|
+
* Charges credits — server returns 402 if balance is insufficient.
|
|
1323
|
+
*/
|
|
1324
|
+
async draft(replyId, channel = "email") {
|
|
1325
|
+
const resp = await fetch(
|
|
1326
|
+
`${baseUrl}/api/v1/inbox/${replyId}/draft${toQuery({ channel })}`,
|
|
1327
|
+
{ headers: headers() }
|
|
1328
|
+
);
|
|
1329
|
+
const data = await resp.json();
|
|
1330
|
+
return data.data || data;
|
|
1331
|
+
},
|
|
1332
|
+
/** Send a reply through email, SMS, or LinkedIn. */
|
|
1333
|
+
async send(replyId, payload) {
|
|
1334
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox/${replyId}/send`, {
|
|
1335
|
+
method: "POST",
|
|
1336
|
+
headers: headers(),
|
|
1337
|
+
body: JSON.stringify(payload)
|
|
1338
|
+
});
|
|
1339
|
+
const data = await resp.json();
|
|
1340
|
+
return data.data || data;
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
};
|
|
1344
|
+
|
|
1038
1345
|
// src/core.ts
|
|
1039
1346
|
var DEFAULT_HOST = "https://t.graph8.com";
|
|
1040
|
-
var
|
|
1347
|
+
var DEFAULT_API23 = "https://be.graph8.com";
|
|
1041
1348
|
var G8 = class {
|
|
1042
1349
|
constructor() {
|
|
1043
1350
|
/** @internal */
|
|
@@ -1086,6 +1393,8 @@ var G8 = class {
|
|
|
1086
1393
|
this._fields = null;
|
|
1087
1394
|
/** @internal */
|
|
1088
1395
|
this._deals = null;
|
|
1396
|
+
/** @internal */
|
|
1397
|
+
this._inbox = null;
|
|
1089
1398
|
}
|
|
1090
1399
|
/**
|
|
1091
1400
|
* Initialize the graph8 SDK. Must be called before any other method.
|
|
@@ -1100,7 +1409,7 @@ var G8 = class {
|
|
|
1100
1409
|
debug: config.debug
|
|
1101
1410
|
});
|
|
1102
1411
|
}
|
|
1103
|
-
const apiUrl = config.apiUrl ||
|
|
1412
|
+
const apiUrl = config.apiUrl || DEFAULT_API23;
|
|
1104
1413
|
const writeKey = config.writeKey || "";
|
|
1105
1414
|
const apiKey = config.apiKey || "";
|
|
1106
1415
|
if (writeKey) {
|
|
@@ -1127,6 +1436,7 @@ var G8 = class {
|
|
|
1127
1436
|
this._tasks = createTasksClient(apiKey, apiUrl);
|
|
1128
1437
|
this._fields = createFieldsClient(apiKey, apiUrl);
|
|
1129
1438
|
this._deals = createDealsClient(apiKey, apiUrl);
|
|
1439
|
+
this._inbox = createInboxClient(apiKey, apiUrl);
|
|
1130
1440
|
this._signals = createSignalsClient(apiKey, true, apiUrl);
|
|
1131
1441
|
}
|
|
1132
1442
|
}
|
|
@@ -1253,6 +1563,11 @@ var G8 = class {
|
|
|
1253
1563
|
this._assertKey("deals");
|
|
1254
1564
|
return this._deals;
|
|
1255
1565
|
}
|
|
1566
|
+
/** Multi-channel inbox — read + reply across email, SMS, LinkedIn (requires API key). */
|
|
1567
|
+
get inbox() {
|
|
1568
|
+
this._assertKey("inbox");
|
|
1569
|
+
return this._inbox;
|
|
1570
|
+
}
|
|
1256
1571
|
/** Whether the SDK has been initialized. */
|
|
1257
1572
|
get initialized() {
|
|
1258
1573
|
return this.config !== null;
|