@graph8/sdk 0.2.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/dist/index.d.mts +1085 -9
- package/dist/index.d.ts +1085 -9
- package/dist/index.js +637 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +637 -8
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +1079 -15
- package/dist/react.d.ts +1079 -15
- package/dist/react.js +637 -8
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +637 -8
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -352,18 +352,133 @@ var DEFAULT_API7 = "https://be.graph8.com";
|
|
|
352
352
|
var createSequencesClient = (apiKey, apiUrl) => {
|
|
353
353
|
const baseUrl = apiUrl || DEFAULT_API7;
|
|
354
354
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
355
|
+
const toQuery = (params) => {
|
|
356
|
+
const qs = new URLSearchParams();
|
|
357
|
+
for (const [k, v] of Object.entries(params)) {
|
|
358
|
+
if (v != null) qs.set(k, String(v));
|
|
359
|
+
}
|
|
360
|
+
const s = qs.toString();
|
|
361
|
+
return s ? `?${s}` : "";
|
|
362
|
+
};
|
|
363
|
+
async function list(pageOrParams, limit) {
|
|
364
|
+
let params;
|
|
365
|
+
if (typeof pageOrParams === "number") {
|
|
366
|
+
params = { page: pageOrParams, limit: limit ?? 50 };
|
|
367
|
+
} else {
|
|
368
|
+
params = pageOrParams ?? {};
|
|
369
|
+
}
|
|
370
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences${toQuery(params)}`, { headers: headers() });
|
|
371
|
+
const data = await resp.json();
|
|
372
|
+
return data.data || data;
|
|
373
|
+
}
|
|
355
374
|
return {
|
|
356
|
-
|
|
357
|
-
|
|
375
|
+
/** List sequences with pagination + optional status filter. */
|
|
376
|
+
list,
|
|
377
|
+
/** Get full sequence details by ID. */
|
|
378
|
+
async get(sequenceId) {
|
|
379
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, { headers: headers() });
|
|
358
380
|
const data = await resp.json();
|
|
359
381
|
return data.data || data;
|
|
360
382
|
},
|
|
383
|
+
/** List contacts enrolled in a sequence. Filter by state (e.g. "active", "replied"). */
|
|
384
|
+
async contacts(sequenceId, params = {}) {
|
|
385
|
+
const resp = await fetch(
|
|
386
|
+
`${baseUrl}/api/v1/sequences/${sequenceId}/contacts${toQuery(params)}`,
|
|
387
|
+
{ headers: headers() }
|
|
388
|
+
);
|
|
389
|
+
return resp.json();
|
|
390
|
+
},
|
|
391
|
+
/** Add contacts to a sequence (V2 queuing). Live or drafted sequences only. */
|
|
361
392
|
async add(config) {
|
|
362
|
-
await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
393
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${config.sequenceId}/contacts`, {
|
|
363
394
|
method: "POST",
|
|
364
395
|
headers: headers(),
|
|
365
396
|
body: JSON.stringify({ contact_ids: config.contactIds, list_id: config.listId })
|
|
366
397
|
});
|
|
398
|
+
const data = await resp.json();
|
|
399
|
+
return data.data || data;
|
|
400
|
+
},
|
|
401
|
+
/** Create a new sequence with optional steps + channels. */
|
|
402
|
+
async create(payload) {
|
|
403
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences`, {
|
|
404
|
+
method: "POST",
|
|
405
|
+
headers: headers(),
|
|
406
|
+
body: JSON.stringify(payload)
|
|
407
|
+
});
|
|
408
|
+
const data = await resp.json();
|
|
409
|
+
return data.data || data;
|
|
410
|
+
},
|
|
411
|
+
/** Update sequence metadata. Rejected (409) if sequence is in a transitional status. */
|
|
412
|
+
async update(sequenceId, fields) {
|
|
413
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
414
|
+
method: "PATCH",
|
|
415
|
+
headers: headers(),
|
|
416
|
+
body: JSON.stringify(fields)
|
|
417
|
+
});
|
|
418
|
+
const data = await resp.json();
|
|
419
|
+
return data.data || data;
|
|
420
|
+
},
|
|
421
|
+
/** Update a single step within a sequence. */
|
|
422
|
+
async updateStep(sequenceId, stepId, fields) {
|
|
423
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/steps/${stepId}`, {
|
|
424
|
+
method: "PATCH",
|
|
425
|
+
headers: headers(),
|
|
426
|
+
body: JSON.stringify(fields)
|
|
427
|
+
});
|
|
428
|
+
const data = await resp.json();
|
|
429
|
+
return data.data || data;
|
|
430
|
+
},
|
|
431
|
+
/** Soft-delete (archive) a sequence. */
|
|
432
|
+
async delete(sequenceId) {
|
|
433
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}`, {
|
|
434
|
+
method: "DELETE",
|
|
435
|
+
headers: headers()
|
|
436
|
+
});
|
|
437
|
+
const data = await resp.json();
|
|
438
|
+
return data.data || data;
|
|
439
|
+
},
|
|
440
|
+
/** Run/start a DRAFTED sequence (V2 orchestration). */
|
|
441
|
+
async run(sequenceId) {
|
|
442
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/run`, {
|
|
443
|
+
method: "POST",
|
|
444
|
+
headers: headers()
|
|
445
|
+
});
|
|
446
|
+
const data = await resp.json();
|
|
447
|
+
return data.data || data;
|
|
448
|
+
},
|
|
449
|
+
/** Pause a live sequence. */
|
|
450
|
+
async pause(sequenceId) {
|
|
451
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/pause`, {
|
|
452
|
+
method: "POST",
|
|
453
|
+
headers: headers()
|
|
454
|
+
});
|
|
455
|
+
const data = await resp.json();
|
|
456
|
+
return data.data || data;
|
|
457
|
+
},
|
|
458
|
+
/** Resume a paused sequence. */
|
|
459
|
+
async resume(sequenceId) {
|
|
460
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/resume`, {
|
|
461
|
+
method: "POST",
|
|
462
|
+
headers: headers()
|
|
463
|
+
});
|
|
464
|
+
const data = await resp.json();
|
|
465
|
+
return data.data || data;
|
|
466
|
+
},
|
|
467
|
+
/** Read-only sequence preview with all steps + channels (no enrollment). */
|
|
468
|
+
async preview(sequenceId) {
|
|
469
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/preview`, {
|
|
470
|
+
headers: headers()
|
|
471
|
+
});
|
|
472
|
+
const data = await resp.json();
|
|
473
|
+
return data.data || data;
|
|
474
|
+
},
|
|
475
|
+
/** Comprehensive analytics for a sequence. */
|
|
476
|
+
async analytics(sequenceId) {
|
|
477
|
+
const resp = await fetch(`${baseUrl}/api/v1/sequences/${sequenceId}/analytics`, {
|
|
478
|
+
headers: headers()
|
|
479
|
+
});
|
|
480
|
+
const data = await resp.json();
|
|
481
|
+
return data.data || data;
|
|
367
482
|
}
|
|
368
483
|
};
|
|
369
484
|
};
|
|
@@ -488,8 +603,116 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
488
603
|
const baseUrl = apiUrl || DEFAULT_API12;
|
|
489
604
|
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
490
605
|
const listeners = /* @__PURE__ */ new Map();
|
|
606
|
+
const toQuery = (params) => {
|
|
607
|
+
const qs = new URLSearchParams();
|
|
608
|
+
for (const [k, v] of Object.entries(params)) {
|
|
609
|
+
if (v != null) qs.set(k, String(v));
|
|
610
|
+
}
|
|
611
|
+
const s = qs.toString();
|
|
612
|
+
return s ? `?${s}` : "";
|
|
613
|
+
};
|
|
614
|
+
const dialer = {
|
|
615
|
+
/** List parallel-dialer sessions with filters + pagination. */
|
|
616
|
+
async listSessions(params = {}) {
|
|
617
|
+
const resp = await fetch(
|
|
618
|
+
`${baseUrl}/api/v1/voice/dialer/sessions${toQuery(params)}`,
|
|
619
|
+
{ headers: headers() }
|
|
620
|
+
);
|
|
621
|
+
const data = await resp.json();
|
|
622
|
+
return data.data || data;
|
|
623
|
+
},
|
|
624
|
+
/** Create a parallel-dialer session in PAUSED state. SDR opens UI to start dialing. */
|
|
625
|
+
async createSession(payload) {
|
|
626
|
+
const resp = await fetch(`${baseUrl}/api/v1/voice/dialer/sessions`, {
|
|
627
|
+
method: "POST",
|
|
628
|
+
headers: headers(),
|
|
629
|
+
body: JSON.stringify(payload)
|
|
630
|
+
});
|
|
631
|
+
const data = await resp.json();
|
|
632
|
+
return data.data || data;
|
|
633
|
+
},
|
|
634
|
+
/** Pause / resume / stop a dialer session via status flip. */
|
|
635
|
+
async updateSessionStatus(sessionId, status) {
|
|
636
|
+
const resp = await fetch(
|
|
637
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/status`,
|
|
638
|
+
{
|
|
639
|
+
method: "PATCH",
|
|
640
|
+
headers: headers(),
|
|
641
|
+
body: JSON.stringify({ status })
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
const data = await resp.json();
|
|
645
|
+
return data.data || data;
|
|
646
|
+
},
|
|
647
|
+
/**
|
|
648
|
+
* Resume a PAUSED dialer session. Auto-fetches the next batch from the source list,
|
|
649
|
+
* filters already-called + phoneless rows, and forwards to voice's start-session.
|
|
650
|
+
* @param maxContacts 1-4 (voice caps parallel dialing at 4). Default 4.
|
|
651
|
+
*/
|
|
652
|
+
async resumeSession(sessionId, maxContacts = 4) {
|
|
653
|
+
const resp = await fetch(
|
|
654
|
+
`${baseUrl}/api/v1/voice/dialer/sessions/${sessionId}/resume`,
|
|
655
|
+
{
|
|
656
|
+
method: "POST",
|
|
657
|
+
headers: headers(),
|
|
658
|
+
body: JSON.stringify({ max_contacts: maxContacts })
|
|
659
|
+
}
|
|
660
|
+
);
|
|
661
|
+
const data = await resp.json();
|
|
662
|
+
return data.data || data;
|
|
663
|
+
},
|
|
664
|
+
/** Aggregated dialer analytics (daily breakdown or total). */
|
|
665
|
+
async stats(params = {}) {
|
|
666
|
+
const resp = await fetch(
|
|
667
|
+
`${baseUrl}/api/v1/voice/dialer/stats${toQuery(params)}`,
|
|
668
|
+
{ headers: headers() }
|
|
669
|
+
);
|
|
670
|
+
const data = await resp.json();
|
|
671
|
+
return data.data || data;
|
|
672
|
+
},
|
|
673
|
+
/** List dialer-eligible phone numbers with 7-day stats + daily limits. */
|
|
674
|
+
async numbers(userEmail) {
|
|
675
|
+
const params = userEmail ? { user_email: userEmail } : {};
|
|
676
|
+
const resp = await fetch(
|
|
677
|
+
`${baseUrl}/api/v1/voice/dialer/numbers${toQuery(params)}`,
|
|
678
|
+
{ headers: headers() }
|
|
679
|
+
);
|
|
680
|
+
const data = await resp.json();
|
|
681
|
+
return data.data || data;
|
|
682
|
+
},
|
|
683
|
+
/** List missed inbound callbacks with caller / contact info. */
|
|
684
|
+
async missedCallbacks(limit = 50) {
|
|
685
|
+
const resp = await fetch(
|
|
686
|
+
`${baseUrl}/api/v1/voice/dialer/missed-callbacks${toQuery({ limit })}`,
|
|
687
|
+
{ headers: headers() }
|
|
688
|
+
);
|
|
689
|
+
const data = await resp.json();
|
|
690
|
+
return data.data || data;
|
|
691
|
+
},
|
|
692
|
+
/** AI grading for a single dialer call (returns "pending" while in progress). */
|
|
693
|
+
async callGrading(roomName) {
|
|
694
|
+
const resp = await fetch(
|
|
695
|
+
`${baseUrl}/api/v1/voice/dialer/calls/${encodeURIComponent(roomName)}/grading`,
|
|
696
|
+
{ headers: headers() }
|
|
697
|
+
);
|
|
698
|
+
const data = await resp.json();
|
|
699
|
+
return data.data || data;
|
|
700
|
+
},
|
|
701
|
+
/** List voice agents available for dialer sessions (capped at 100; no pagination). */
|
|
702
|
+
async agents(params = {}) {
|
|
703
|
+
const resp = await fetch(
|
|
704
|
+
`${baseUrl}/api/v1/voice/dialer/agents${toQuery(params)}`,
|
|
705
|
+
{ headers: headers() }
|
|
706
|
+
);
|
|
707
|
+
const data = await resp.json();
|
|
708
|
+
return data.data || data;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
491
711
|
return {
|
|
492
|
-
/**
|
|
712
|
+
/**
|
|
713
|
+
* Start an AI voice session.
|
|
714
|
+
* @deprecated Preview surface — for parallel-dialer flows use `voice.dialer.createSession()`.
|
|
715
|
+
*/
|
|
493
716
|
async start(config) {
|
|
494
717
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions`, {
|
|
495
718
|
method: "POST",
|
|
@@ -499,7 +722,10 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
499
722
|
const data = await resp.json();
|
|
500
723
|
return data.data || data;
|
|
501
724
|
},
|
|
502
|
-
/**
|
|
725
|
+
/**
|
|
726
|
+
* Get call analysis for a completed session.
|
|
727
|
+
* @deprecated Preview surface — for dialer-call grading use `voice.dialer.callGrading(roomName)`.
|
|
728
|
+
*/
|
|
503
729
|
async analysis(sessionId) {
|
|
504
730
|
const resp = await fetch(`${baseUrl}/api/v1/voice/sessions/${sessionId}/analysis`, { headers: headers() });
|
|
505
731
|
const data = await resp.json();
|
|
@@ -509,7 +735,9 @@ var createVoiceClient = (apiKey, apiUrl) => {
|
|
|
509
735
|
on(event, callback) {
|
|
510
736
|
if (!listeners.has(event)) listeners.set(event, []);
|
|
511
737
|
listeners.get(event).push(callback);
|
|
512
|
-
}
|
|
738
|
+
},
|
|
739
|
+
/** Parallel-dialer session control + analytics. */
|
|
740
|
+
dialer
|
|
513
741
|
};
|
|
514
742
|
};
|
|
515
743
|
|
|
@@ -641,6 +869,28 @@ var createContactsClient = (apiKey, apiUrl) => {
|
|
|
641
869
|
headers: headers()
|
|
642
870
|
});
|
|
643
871
|
return resp.json();
|
|
872
|
+
},
|
|
873
|
+
/** List custom contact columns. Pass listId to include list-specific columns. */
|
|
874
|
+
async listColumns(listId) {
|
|
875
|
+
const qs = listId != null ? `?list_id=${listId}` : "";
|
|
876
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/columns${qs}`, { headers: headers() });
|
|
877
|
+
return resp.json();
|
|
878
|
+
},
|
|
879
|
+
/** Create a custom contact column. Global if list_id is omitted, list-scoped otherwise. */
|
|
880
|
+
async createColumn(params) {
|
|
881
|
+
const body = {
|
|
882
|
+
title: params.title,
|
|
883
|
+
data_type: params.data_type || "text",
|
|
884
|
+
list_id: params.list_id ?? null,
|
|
885
|
+
created_by: params.created_by
|
|
886
|
+
};
|
|
887
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/columns/create`, {
|
|
888
|
+
method: "POST",
|
|
889
|
+
headers: headers(),
|
|
890
|
+
body: JSON.stringify(body)
|
|
891
|
+
});
|
|
892
|
+
const data = await resp.json();
|
|
893
|
+
return data.data || data;
|
|
644
894
|
}
|
|
645
895
|
};
|
|
646
896
|
};
|
|
@@ -694,6 +944,28 @@ var createCompaniesClient = (apiKey, apiUrl) => {
|
|
|
694
944
|
headers: headers()
|
|
695
945
|
});
|
|
696
946
|
return resp.json();
|
|
947
|
+
},
|
|
948
|
+
/** List custom company columns. Pass listId to include list-specific columns. */
|
|
949
|
+
async listColumns(listId) {
|
|
950
|
+
const qs = listId != null ? `?list_id=${listId}` : "";
|
|
951
|
+
const resp = await fetch(`${baseUrl}/api/v1/companies/columns${qs}`, { headers: headers() });
|
|
952
|
+
return resp.json();
|
|
953
|
+
},
|
|
954
|
+
/** Create a custom company column. Global if list_id is omitted, list-scoped otherwise. */
|
|
955
|
+
async createColumn(params) {
|
|
956
|
+
const body = {
|
|
957
|
+
title: params.title,
|
|
958
|
+
data_type: params.data_type || "text",
|
|
959
|
+
list_id: params.list_id ?? null,
|
|
960
|
+
created_by: params.created_by
|
|
961
|
+
};
|
|
962
|
+
const resp = await fetch(`${baseUrl}/api/v1/companies/columns/create`, {
|
|
963
|
+
method: "POST",
|
|
964
|
+
headers: headers(),
|
|
965
|
+
body: JSON.stringify(body)
|
|
966
|
+
});
|
|
967
|
+
const data = await resp.json();
|
|
968
|
+
return data.data || data;
|
|
697
969
|
}
|
|
698
970
|
};
|
|
699
971
|
};
|
|
@@ -756,9 +1028,326 @@ var createListsClient = (apiKey, apiUrl) => {
|
|
|
756
1028
|
};
|
|
757
1029
|
};
|
|
758
1030
|
|
|
1031
|
+
// src/notes.ts
|
|
1032
|
+
var DEFAULT_API18 = "https://be.graph8.com";
|
|
1033
|
+
var createNotesClient = (apiKey, apiUrl) => {
|
|
1034
|
+
const baseUrl = apiUrl || DEFAULT_API18;
|
|
1035
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1036
|
+
return {
|
|
1037
|
+
/** List all notes on a contact. */
|
|
1038
|
+
async list(contactId) {
|
|
1039
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/${contactId}/notes`, { headers: headers() });
|
|
1040
|
+
return resp.json();
|
|
1041
|
+
},
|
|
1042
|
+
/** Create a note on a contact. */
|
|
1043
|
+
async create(contactId, content) {
|
|
1044
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/${contactId}/notes`, {
|
|
1045
|
+
method: "POST",
|
|
1046
|
+
headers: headers(),
|
|
1047
|
+
body: JSON.stringify({ content })
|
|
1048
|
+
});
|
|
1049
|
+
const data = await resp.json();
|
|
1050
|
+
return data.data || data;
|
|
1051
|
+
},
|
|
1052
|
+
/** Update a note's content. */
|
|
1053
|
+
async update(noteId, content) {
|
|
1054
|
+
const resp = await fetch(`${baseUrl}/api/v1/notes/${noteId}`, {
|
|
1055
|
+
method: "PATCH",
|
|
1056
|
+
headers: headers(),
|
|
1057
|
+
body: JSON.stringify({ content })
|
|
1058
|
+
});
|
|
1059
|
+
const data = await resp.json();
|
|
1060
|
+
return data.data || data;
|
|
1061
|
+
},
|
|
1062
|
+
/** Delete a note. */
|
|
1063
|
+
async delete(noteId) {
|
|
1064
|
+
const resp = await fetch(`${baseUrl}/api/v1/notes/${noteId}`, {
|
|
1065
|
+
method: "DELETE",
|
|
1066
|
+
headers: headers()
|
|
1067
|
+
});
|
|
1068
|
+
return resp.json();
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// src/tasks.ts
|
|
1074
|
+
var DEFAULT_API19 = "https://be.graph8.com";
|
|
1075
|
+
var createTasksClient = (apiKey, apiUrl) => {
|
|
1076
|
+
const baseUrl = apiUrl || DEFAULT_API19;
|
|
1077
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1078
|
+
const toQuery = (params) => {
|
|
1079
|
+
const qs = new URLSearchParams();
|
|
1080
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1081
|
+
if (v != null) qs.set(k, String(v));
|
|
1082
|
+
}
|
|
1083
|
+
const s = qs.toString();
|
|
1084
|
+
return s ? `?${s}` : "";
|
|
1085
|
+
};
|
|
1086
|
+
return {
|
|
1087
|
+
/** List tasks on a single contact. Optional status filter ("open" | "completed"). */
|
|
1088
|
+
async listForContact(contactId, status) {
|
|
1089
|
+
const qs = status ? `?status=${encodeURIComponent(status)}` : "";
|
|
1090
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/${contactId}/tasks${qs}`, { headers: headers() });
|
|
1091
|
+
return resp.json();
|
|
1092
|
+
},
|
|
1093
|
+
/** List all tasks org-wide with optional filters. */
|
|
1094
|
+
async list(params = {}) {
|
|
1095
|
+
const resp = await fetch(`${baseUrl}/api/v1/tasks${toQuery(params)}`, { headers: headers() });
|
|
1096
|
+
return resp.json();
|
|
1097
|
+
},
|
|
1098
|
+
/** Create a task on a contact. */
|
|
1099
|
+
async create(contactId, task) {
|
|
1100
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/${contactId}/tasks`, {
|
|
1101
|
+
method: "POST",
|
|
1102
|
+
headers: headers(),
|
|
1103
|
+
body: JSON.stringify(task)
|
|
1104
|
+
});
|
|
1105
|
+
const data = await resp.json();
|
|
1106
|
+
return data.data || data;
|
|
1107
|
+
},
|
|
1108
|
+
/** Update a task (partial). */
|
|
1109
|
+
async update(taskId, fields) {
|
|
1110
|
+
const resp = await fetch(`${baseUrl}/api/v1/tasks/${taskId}`, {
|
|
1111
|
+
method: "PATCH",
|
|
1112
|
+
headers: headers(),
|
|
1113
|
+
body: JSON.stringify(fields)
|
|
1114
|
+
});
|
|
1115
|
+
const data = await resp.json();
|
|
1116
|
+
return data.data || data;
|
|
1117
|
+
},
|
|
1118
|
+
/** Delete a task. */
|
|
1119
|
+
async delete(taskId) {
|
|
1120
|
+
const resp = await fetch(`${baseUrl}/api/v1/tasks/${taskId}`, {
|
|
1121
|
+
method: "DELETE",
|
|
1122
|
+
headers: headers()
|
|
1123
|
+
});
|
|
1124
|
+
return resp.json();
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
// src/fields.ts
|
|
1130
|
+
var DEFAULT_API20 = "https://be.graph8.com";
|
|
1131
|
+
var createFieldsClient = (apiKey, apiUrl) => {
|
|
1132
|
+
const baseUrl = apiUrl || DEFAULT_API20;
|
|
1133
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1134
|
+
const toQuery = (params) => {
|
|
1135
|
+
const qs = new URLSearchParams();
|
|
1136
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1137
|
+
if (v != null) qs.set(k, String(v));
|
|
1138
|
+
}
|
|
1139
|
+
const s = qs.toString();
|
|
1140
|
+
return s ? `?${s}` : "";
|
|
1141
|
+
};
|
|
1142
|
+
return {
|
|
1143
|
+
/** List contact fields (base + custom). Pass listId to include list-specific custom fields. */
|
|
1144
|
+
async listContactFields(listId) {
|
|
1145
|
+
const qs = listId != null ? `?list_id=${listId}` : "";
|
|
1146
|
+
const resp = await fetch(`${baseUrl}/api/v1/fields${qs}`, { headers: headers() });
|
|
1147
|
+
return resp.json();
|
|
1148
|
+
},
|
|
1149
|
+
/** List company fields (base + custom). Pass listId to include list-specific custom fields. */
|
|
1150
|
+
async listCompanyFields(listId) {
|
|
1151
|
+
const qs = listId != null ? `?list_id=${listId}` : "";
|
|
1152
|
+
const resp = await fetch(`${baseUrl}/api/v1/fields/companies${qs}`, { headers: headers() });
|
|
1153
|
+
return resp.json();
|
|
1154
|
+
},
|
|
1155
|
+
/** Create a custom field on contacts (default) or companies. */
|
|
1156
|
+
async create(params) {
|
|
1157
|
+
const body = {
|
|
1158
|
+
title: params.title,
|
|
1159
|
+
data_type: params.data_type || "text",
|
|
1160
|
+
list_id: params.list_id ?? null,
|
|
1161
|
+
entity: params.entity || "contacts"
|
|
1162
|
+
};
|
|
1163
|
+
const resp = await fetch(`${baseUrl}/api/v1/fields`, {
|
|
1164
|
+
method: "POST",
|
|
1165
|
+
headers: headers(),
|
|
1166
|
+
body: JSON.stringify(body)
|
|
1167
|
+
});
|
|
1168
|
+
const data = await resp.json();
|
|
1169
|
+
return data.data || data;
|
|
1170
|
+
},
|
|
1171
|
+
/** Delete a custom field (soft-delete). Pass list_id to scope-guard against cross-list deletion. */
|
|
1172
|
+
async delete(columnId, params = {}) {
|
|
1173
|
+
const queryParams = { entity: params.entity || "contacts" };
|
|
1174
|
+
if (params.list_id != null) queryParams.list_id = params.list_id;
|
|
1175
|
+
const resp = await fetch(`${baseUrl}/api/v1/fields/${columnId}${toQuery(queryParams)}`, {
|
|
1176
|
+
method: "DELETE",
|
|
1177
|
+
headers: headers()
|
|
1178
|
+
});
|
|
1179
|
+
return resp.json();
|
|
1180
|
+
},
|
|
1181
|
+
/** Set a custom field value on a single contact or company row. Pass value=null to clear. */
|
|
1182
|
+
async setValue(columnId, params) {
|
|
1183
|
+
const body = {
|
|
1184
|
+
record_id: params.record_id,
|
|
1185
|
+
value: params.value ?? null,
|
|
1186
|
+
entity: params.entity || "contacts"
|
|
1187
|
+
};
|
|
1188
|
+
const resp = await fetch(`${baseUrl}/api/v1/fields/${columnId}/values`, {
|
|
1189
|
+
method: "PATCH",
|
|
1190
|
+
headers: headers(),
|
|
1191
|
+
body: JSON.stringify(body)
|
|
1192
|
+
});
|
|
1193
|
+
return resp.json();
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
// src/deals.ts
|
|
1199
|
+
var DEFAULT_API21 = "https://be.graph8.com";
|
|
1200
|
+
var createDealsClient = (apiKey, apiUrl) => {
|
|
1201
|
+
const baseUrl = apiUrl || DEFAULT_API21;
|
|
1202
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1203
|
+
const toQuery = (params) => {
|
|
1204
|
+
const qs = new URLSearchParams();
|
|
1205
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1206
|
+
if (v != null) qs.set(k, String(v));
|
|
1207
|
+
}
|
|
1208
|
+
const s = qs.toString();
|
|
1209
|
+
return s ? `?${s}` : "";
|
|
1210
|
+
};
|
|
1211
|
+
return {
|
|
1212
|
+
/** List all deal pipelines and their stages. */
|
|
1213
|
+
async pipelines() {
|
|
1214
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals/pipelines`, { headers: headers() });
|
|
1215
|
+
return resp.json();
|
|
1216
|
+
},
|
|
1217
|
+
/** List deals org-wide with optional filters and pagination. */
|
|
1218
|
+
async list(params = {}) {
|
|
1219
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals${toQuery(params)}`, { headers: headers() });
|
|
1220
|
+
return resp.json();
|
|
1221
|
+
},
|
|
1222
|
+
/** Create a new deal. */
|
|
1223
|
+
async create(deal) {
|
|
1224
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals`, {
|
|
1225
|
+
method: "POST",
|
|
1226
|
+
headers: headers(),
|
|
1227
|
+
body: JSON.stringify(deal)
|
|
1228
|
+
});
|
|
1229
|
+
const data = await resp.json();
|
|
1230
|
+
return data.data || data;
|
|
1231
|
+
},
|
|
1232
|
+
/** Get a single deal by ID. */
|
|
1233
|
+
async get(dealId) {
|
|
1234
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals/${dealId}`, { headers: headers() });
|
|
1235
|
+
const data = await resp.json();
|
|
1236
|
+
return data.data || data;
|
|
1237
|
+
},
|
|
1238
|
+
/** Update a deal (partial). */
|
|
1239
|
+
async update(dealId, fields) {
|
|
1240
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals/${dealId}`, {
|
|
1241
|
+
method: "PATCH",
|
|
1242
|
+
headers: headers(),
|
|
1243
|
+
body: JSON.stringify(fields)
|
|
1244
|
+
});
|
|
1245
|
+
const data = await resp.json();
|
|
1246
|
+
return data.data || data;
|
|
1247
|
+
},
|
|
1248
|
+
/** Delete a deal. */
|
|
1249
|
+
async delete(dealId) {
|
|
1250
|
+
const resp = await fetch(`${baseUrl}/api/v1/deals/${dealId}`, {
|
|
1251
|
+
method: "DELETE",
|
|
1252
|
+
headers: headers()
|
|
1253
|
+
});
|
|
1254
|
+
return resp.json();
|
|
1255
|
+
},
|
|
1256
|
+
/** Get all deals associated with a contact. */
|
|
1257
|
+
async forContact(contactId) {
|
|
1258
|
+
const resp = await fetch(`${baseUrl}/api/v1/contacts/${contactId}/deals`, { headers: headers() });
|
|
1259
|
+
return resp.json();
|
|
1260
|
+
},
|
|
1261
|
+
/** Get all deals associated with a company. */
|
|
1262
|
+
async forCompany(companyId) {
|
|
1263
|
+
const resp = await fetch(`${baseUrl}/api/v1/companies/${companyId}/deals`, { headers: headers() });
|
|
1264
|
+
return resp.json();
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
// src/inbox.ts
|
|
1270
|
+
var DEFAULT_API22 = "https://be.graph8.com";
|
|
1271
|
+
var createInboxClient = (apiKey, apiUrl) => {
|
|
1272
|
+
const baseUrl = apiUrl || DEFAULT_API22;
|
|
1273
|
+
const headers = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` });
|
|
1274
|
+
const toQuery = (params) => {
|
|
1275
|
+
const qs = new URLSearchParams();
|
|
1276
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1277
|
+
if (v != null) qs.set(k, String(v));
|
|
1278
|
+
}
|
|
1279
|
+
const s = qs.toString();
|
|
1280
|
+
return s ? `?${s}` : "";
|
|
1281
|
+
};
|
|
1282
|
+
return {
|
|
1283
|
+
/** List inbox threads across email, SMS, and LinkedIn. */
|
|
1284
|
+
async list(params = {}) {
|
|
1285
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox${toQuery(params)}`, { headers: headers() });
|
|
1286
|
+
return resp.json();
|
|
1287
|
+
},
|
|
1288
|
+
/** Get a single inbox thread. Defaults to email channel. */
|
|
1289
|
+
async get(replyId, channel = "email") {
|
|
1290
|
+
const resp = await fetch(
|
|
1291
|
+
`${baseUrl}/api/v1/inbox/${replyId}${toQuery({ channel })}`,
|
|
1292
|
+
{ headers: headers() }
|
|
1293
|
+
);
|
|
1294
|
+
const data = await resp.json();
|
|
1295
|
+
return data.data || data;
|
|
1296
|
+
},
|
|
1297
|
+
/** Assign a user to an inbox thread. */
|
|
1298
|
+
async assign(replyId, assigneeEmail, channel = "email") {
|
|
1299
|
+
const resp = await fetch(
|
|
1300
|
+
`${baseUrl}/api/v1/inbox/${replyId}/assign${toQuery({ channel })}`,
|
|
1301
|
+
{
|
|
1302
|
+
method: "POST",
|
|
1303
|
+
headers: headers(),
|
|
1304
|
+
body: JSON.stringify({ assignee_email: assigneeEmail })
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
const data = await resp.json();
|
|
1308
|
+
return data.data || data;
|
|
1309
|
+
},
|
|
1310
|
+
/** Attach tag IDs to an inbox thread. */
|
|
1311
|
+
async tag(replyId, tagIds, channel = "email") {
|
|
1312
|
+
const resp = await fetch(
|
|
1313
|
+
`${baseUrl}/api/v1/inbox/${replyId}/tag${toQuery({ channel })}`,
|
|
1314
|
+
{
|
|
1315
|
+
method: "POST",
|
|
1316
|
+
headers: headers(),
|
|
1317
|
+
body: JSON.stringify({ tag_ids: tagIds })
|
|
1318
|
+
}
|
|
1319
|
+
);
|
|
1320
|
+
const data = await resp.json();
|
|
1321
|
+
return data.data || data;
|
|
1322
|
+
},
|
|
1323
|
+
/**
|
|
1324
|
+
* Generate an AI draft reply for a thread.
|
|
1325
|
+
* Charges credits — server returns 402 if balance is insufficient.
|
|
1326
|
+
*/
|
|
1327
|
+
async draft(replyId, channel = "email") {
|
|
1328
|
+
const resp = await fetch(
|
|
1329
|
+
`${baseUrl}/api/v1/inbox/${replyId}/draft${toQuery({ channel })}`,
|
|
1330
|
+
{ headers: headers() }
|
|
1331
|
+
);
|
|
1332
|
+
const data = await resp.json();
|
|
1333
|
+
return data.data || data;
|
|
1334
|
+
},
|
|
1335
|
+
/** Send a reply through email, SMS, or LinkedIn. */
|
|
1336
|
+
async send(replyId, payload) {
|
|
1337
|
+
const resp = await fetch(`${baseUrl}/api/v1/inbox/${replyId}/send`, {
|
|
1338
|
+
method: "POST",
|
|
1339
|
+
headers: headers(),
|
|
1340
|
+
body: JSON.stringify(payload)
|
|
1341
|
+
});
|
|
1342
|
+
const data = await resp.json();
|
|
1343
|
+
return data.data || data;
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
};
|
|
1347
|
+
|
|
759
1348
|
// src/core.ts
|
|
760
1349
|
var DEFAULT_HOST = "https://t.graph8.com";
|
|
761
|
-
var
|
|
1350
|
+
var DEFAULT_API23 = "https://be.graph8.com";
|
|
762
1351
|
var G8 = class {
|
|
763
1352
|
constructor() {
|
|
764
1353
|
/** @internal */
|
|
@@ -799,6 +1388,16 @@ var G8 = class {
|
|
|
799
1388
|
this._companies = null;
|
|
800
1389
|
/** @internal */
|
|
801
1390
|
this._lists = null;
|
|
1391
|
+
/** @internal */
|
|
1392
|
+
this._notes = null;
|
|
1393
|
+
/** @internal */
|
|
1394
|
+
this._tasks = null;
|
|
1395
|
+
/** @internal */
|
|
1396
|
+
this._fields = null;
|
|
1397
|
+
/** @internal */
|
|
1398
|
+
this._deals = null;
|
|
1399
|
+
/** @internal */
|
|
1400
|
+
this._inbox = null;
|
|
802
1401
|
}
|
|
803
1402
|
/**
|
|
804
1403
|
* Initialize the graph8 SDK. Must be called before any other method.
|
|
@@ -813,7 +1412,7 @@ var G8 = class {
|
|
|
813
1412
|
debug: config.debug
|
|
814
1413
|
});
|
|
815
1414
|
}
|
|
816
|
-
const apiUrl = config.apiUrl ||
|
|
1415
|
+
const apiUrl = config.apiUrl || DEFAULT_API23;
|
|
817
1416
|
const writeKey = config.writeKey || "";
|
|
818
1417
|
const apiKey = config.apiKey || "";
|
|
819
1418
|
if (writeKey) {
|
|
@@ -836,6 +1435,11 @@ var G8 = class {
|
|
|
836
1435
|
this._contacts = createContactsClient(apiKey, apiUrl);
|
|
837
1436
|
this._companies = createCompaniesClient(apiKey, apiUrl);
|
|
838
1437
|
this._lists = createListsClient(apiKey, apiUrl);
|
|
1438
|
+
this._notes = createNotesClient(apiKey, apiUrl);
|
|
1439
|
+
this._tasks = createTasksClient(apiKey, apiUrl);
|
|
1440
|
+
this._fields = createFieldsClient(apiKey, apiUrl);
|
|
1441
|
+
this._deals = createDealsClient(apiKey, apiUrl);
|
|
1442
|
+
this._inbox = createInboxClient(apiKey, apiUrl);
|
|
839
1443
|
this._signals = createSignalsClient(apiKey, true, apiUrl);
|
|
840
1444
|
}
|
|
841
1445
|
}
|
|
@@ -942,6 +1546,31 @@ var G8 = class {
|
|
|
942
1546
|
this._assertKey("lists");
|
|
943
1547
|
return this._lists;
|
|
944
1548
|
}
|
|
1549
|
+
/** Notes on contacts (requires API key). */
|
|
1550
|
+
get notes() {
|
|
1551
|
+
this._assertKey("notes");
|
|
1552
|
+
return this._notes;
|
|
1553
|
+
}
|
|
1554
|
+
/** Tasks on contacts (requires API key). */
|
|
1555
|
+
get tasks() {
|
|
1556
|
+
this._assertKey("tasks");
|
|
1557
|
+
return this._tasks;
|
|
1558
|
+
}
|
|
1559
|
+
/** Custom fields management (requires API key). */
|
|
1560
|
+
get fields() {
|
|
1561
|
+
this._assertKey("fields");
|
|
1562
|
+
return this._fields;
|
|
1563
|
+
}
|
|
1564
|
+
/** Deals and pipelines (requires API key). */
|
|
1565
|
+
get deals() {
|
|
1566
|
+
this._assertKey("deals");
|
|
1567
|
+
return this._deals;
|
|
1568
|
+
}
|
|
1569
|
+
/** Multi-channel inbox — read + reply across email, SMS, LinkedIn (requires API key). */
|
|
1570
|
+
get inbox() {
|
|
1571
|
+
this._assertKey("inbox");
|
|
1572
|
+
return this._inbox;
|
|
1573
|
+
}
|
|
945
1574
|
/** Whether the SDK has been initialized. */
|
|
946
1575
|
get initialized() {
|
|
947
1576
|
return this.config !== null;
|