@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/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
- async list(page = 1, limit = 50) {
357
- const resp = await fetch(`${baseUrl}/api/v1/sequences?page=${page}&limit=${limit}`, { headers: headers() });
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
- /** Start an AI voice session. */
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
- /** Get call analysis for a completed session. */
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
 
@@ -1038,9 +1266,88 @@ var createDealsClient = (apiKey, apiUrl) => {
1038
1266
  };
1039
1267
  };
1040
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
+
1041
1348
  // src/core.ts
1042
1349
  var DEFAULT_HOST = "https://t.graph8.com";
1043
- var DEFAULT_API22 = "https://be.graph8.com";
1350
+ var DEFAULT_API23 = "https://be.graph8.com";
1044
1351
  var G8 = class {
1045
1352
  constructor() {
1046
1353
  /** @internal */
@@ -1089,6 +1396,8 @@ var G8 = class {
1089
1396
  this._fields = null;
1090
1397
  /** @internal */
1091
1398
  this._deals = null;
1399
+ /** @internal */
1400
+ this._inbox = null;
1092
1401
  }
1093
1402
  /**
1094
1403
  * Initialize the graph8 SDK. Must be called before any other method.
@@ -1103,7 +1412,7 @@ var G8 = class {
1103
1412
  debug: config.debug
1104
1413
  });
1105
1414
  }
1106
- const apiUrl = config.apiUrl || DEFAULT_API22;
1415
+ const apiUrl = config.apiUrl || DEFAULT_API23;
1107
1416
  const writeKey = config.writeKey || "";
1108
1417
  const apiKey = config.apiKey || "";
1109
1418
  if (writeKey) {
@@ -1130,6 +1439,7 @@ var G8 = class {
1130
1439
  this._tasks = createTasksClient(apiKey, apiUrl);
1131
1440
  this._fields = createFieldsClient(apiKey, apiUrl);
1132
1441
  this._deals = createDealsClient(apiKey, apiUrl);
1442
+ this._inbox = createInboxClient(apiKey, apiUrl);
1133
1443
  this._signals = createSignalsClient(apiKey, true, apiUrl);
1134
1444
  }
1135
1445
  }
@@ -1256,6 +1566,11 @@ var G8 = class {
1256
1566
  this._assertKey("deals");
1257
1567
  return this._deals;
1258
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
+ }
1259
1574
  /** Whether the SDK has been initialized. */
1260
1575
  get initialized() {
1261
1576
  return this.config !== null;