@wokuapp/sdk 0.4.0 → 0.6.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.js CHANGED
@@ -36,7 +36,7 @@ var FollowUps = class {
36
36
  };
37
37
 
38
38
  // package.json
39
- var version = "0.4.0";
39
+ var version = "0.6.0";
40
40
 
41
41
  // src/core/errors.ts
42
42
  var WokuError = class extends Error {
@@ -383,7 +383,8 @@ var WokuClient = class {
383
383
  headers,
384
384
  bodyText,
385
385
  timeout,
386
- args.signal
386
+ args.signal,
387
+ args.binary
387
388
  );
388
389
  if (status >= 200 && status < 300) {
389
390
  return body;
@@ -500,7 +501,7 @@ var WokuClient = class {
500
501
  }
501
502
  return headers;
502
503
  }
503
- async send(url, method, headers, body, timeout, signal) {
504
+ async send(url, method, headers, body, timeout, signal, binary) {
504
505
  if (signal?.aborted)
505
506
  throw new WokuConnectionError("Request aborted", { code: "aborted" });
506
507
  const controller = new AbortController();
@@ -521,6 +522,20 @@ var WokuClient = class {
521
522
  body,
522
523
  signal: controller.signal
523
524
  });
525
+ if (binary && response.status >= 200 && response.status < 300) {
526
+ if (!response.arrayBuffer) {
527
+ throw new WokuError(
528
+ "The fetch implementation cannot read binary responses.",
529
+ { code: "config_error" }
530
+ );
531
+ }
532
+ return {
533
+ status: response.status,
534
+ body: new Uint8Array(await response.arrayBuffer()),
535
+ requestId: requestIdFrom(response.headers),
536
+ retryAfterSeconds: retryAfterFromHeaders(response.headers)
537
+ };
538
+ }
524
539
  const text = await response.text();
525
540
  return {
526
541
  status: response.status,
@@ -719,6 +734,14 @@ var NpsTools = class {
719
734
  }
720
735
  );
721
736
  }
737
+ /** Move the tool into a folder, or to the root with `folderId: null`. */
738
+ move(id, body, opts) {
739
+ return this.client.request(
740
+ "patch",
741
+ `/v1/nps-tools/${encodeURIComponent(id)}/move`,
742
+ { ...opts, body }
743
+ );
744
+ }
722
745
  delete(id, opts) {
723
746
  return this.client.request(
724
747
  "delete",
@@ -758,6 +781,14 @@ var CsatTools = class {
758
781
  }
759
782
  );
760
783
  }
784
+ /** Move the tool into a folder, or to the root with `folderId: null`. */
785
+ move(id, body, opts) {
786
+ return this.client.request(
787
+ "patch",
788
+ `/v1/csat-tools/${encodeURIComponent(id)}/move`,
789
+ { ...opts, body }
790
+ );
791
+ }
761
792
  delete(id, opts) {
762
793
  return this.client.request(
763
794
  "delete",
@@ -797,6 +828,14 @@ var CesTools = class {
797
828
  }
798
829
  );
799
830
  }
831
+ /** Move the tool into a folder, or to the root with `folderId: null`. */
832
+ move(id, body, opts) {
833
+ return this.client.request(
834
+ "patch",
835
+ `/v1/ces-tools/${encodeURIComponent(id)}/move`,
836
+ { ...opts, body }
837
+ );
838
+ }
800
839
  delete(id, opts) {
801
840
  return this.client.request(
802
841
  "delete",
@@ -1014,9 +1053,11 @@ var Flows = class {
1014
1053
  constructor(client) {
1015
1054
  this.client = client;
1016
1055
  }
1056
+ /** List the flows of the company, with their ordered `steps`. */
1017
1057
  list(params, opts) {
1018
1058
  return this.client.getPage("/v1/flows", params, opts);
1019
1059
  }
1060
+ /** The data of a flow: ordered steps with their tools, wokus and branding. */
1020
1061
  get(id, opts) {
1021
1062
  return this.client.request(
1022
1063
  "get",
@@ -1024,6 +1065,33 @@ var Flows = class {
1024
1065
  opts
1025
1066
  );
1026
1067
  }
1068
+ /**
1069
+ * Create a flow from 1 to 20 ordered steps (each tool once, all of your
1070
+ * company). Flows live outside folders.
1071
+ */
1072
+ create(body, opts) {
1073
+ return this.client.request("post", "/v1/flows", {
1074
+ ...opts,
1075
+ body,
1076
+ idempotent: true
1077
+ });
1078
+ }
1079
+ /** Rename a flow or replace its full ordered list of steps. */
1080
+ update(id, body, opts) {
1081
+ return this.client.request(
1082
+ "patch",
1083
+ `/v1/flows/${encodeURIComponent(id)}`,
1084
+ { ...opts, body }
1085
+ );
1086
+ }
1087
+ /** Delete a flow. Its tools and their responses stay. */
1088
+ delete(id, opts) {
1089
+ return this.client.request(
1090
+ "delete",
1091
+ `/v1/flows/${encodeURIComponent(id)}`,
1092
+ opts
1093
+ );
1094
+ }
1027
1095
  };
1028
1096
 
1029
1097
  // src/resources/action-plans.ts
@@ -1507,18 +1575,239 @@ var Journeys = class {
1507
1575
  }
1508
1576
  };
1509
1577
 
1510
- // src/resources/quarantines.ts
1511
- var Quarantines = class {
1578
+ // src/resources/folders.ts
1579
+ var Folders = class {
1512
1580
  constructor(client) {
1513
1581
  this.client = client;
1514
1582
  }
1515
- /** Check whether a contact is quarantined. */
1516
- check(params, opts) {
1517
- return this.client.request("get", "/v1/quarantines/check", {
1583
+ /** Every folder of the company, or the direct subfolders of `parentFolderId`. */
1584
+ list(params, opts) {
1585
+ return this.client.request("get", "/v1/folders", {
1518
1586
  ...opts,
1519
1587
  query: { ...params, ...opts?.query }
1520
1588
  });
1521
1589
  }
1590
+ get(id, opts) {
1591
+ return this.client.request(
1592
+ "get",
1593
+ `/v1/folders/${encodeURIComponent(id)}`,
1594
+ opts
1595
+ );
1596
+ }
1597
+ create(body, opts) {
1598
+ return this.client.request("post", "/v1/folders", {
1599
+ ...opts,
1600
+ body,
1601
+ idempotent: true
1602
+ });
1603
+ }
1604
+ /**
1605
+ * Rename or recolor a folder (`color: null` clears the color) and/or replace
1606
+ * its WhatsApp alert recipients (`whatsappAlertRecipients`, `[]` clears them).
1607
+ */
1608
+ update(id, body, opts) {
1609
+ return this.client.request(
1610
+ "patch",
1611
+ `/v1/folders/${encodeURIComponent(id)}`,
1612
+ { ...opts, body }
1613
+ );
1614
+ }
1615
+ /**
1616
+ * Move a folder under another folder, or to the root with
1617
+ * `parentFolderId: null`. A folder cannot move into its own subtree.
1618
+ */
1619
+ move(id, body, opts) {
1620
+ return this.client.request(
1621
+ "patch",
1622
+ `/v1/folders/${encodeURIComponent(id)}/move`,
1623
+ { ...opts, body }
1624
+ );
1625
+ }
1626
+ /**
1627
+ * Delete a folder. Nothing inside is deleted: subfolders, wokus and tools
1628
+ * move up to the parent folder (or the root).
1629
+ */
1630
+ delete(id, opts) {
1631
+ return this.client.request(
1632
+ "delete",
1633
+ `/v1/folders/${encodeURIComponent(id)}`,
1634
+ opts
1635
+ );
1636
+ }
1637
+ /**
1638
+ * AI report over every woku, NPS, CSAT and CES tool of the folder and its
1639
+ * subfolders. Scales differ per type, so there is no rating distribution.
1640
+ */
1641
+ report(id, params, opts) {
1642
+ return this.client.request(
1643
+ "get",
1644
+ `/v1/folders/${encodeURIComponent(id)}/report`,
1645
+ { ...opts, query: { ...params, ...opts?.query } }
1646
+ );
1647
+ }
1648
+ /**
1649
+ * Per-tool figures of the woku, NPS, CSAT and CES tools of the folder and its
1650
+ * subfolders for a period against the one before it, with the daily sums and
1651
+ * the histogram of scores. `days` is 7, 30 (default) or 90, or 0 for the whole
1652
+ * history (every `previous` window is then empty). The period is the last
1653
+ * `days` calendar days in UTC, today included. Or a custom range with `from`
1654
+ * and `to` (`YYYY-MM-DD` UTC days, both inclusive, up to 731 days), which
1655
+ * replaces `days`. Scales are never mixed across types.
1656
+ */
1657
+ metrics(id, params, opts) {
1658
+ return this.client.request(
1659
+ "get",
1660
+ `/v1/folders/${encodeURIComponent(id)}/metrics`,
1661
+ { ...opts, query: { ...params, ...opts?.query } }
1662
+ );
1663
+ }
1664
+ /** CSV text with one row per response of every tool of the folder subtree. */
1665
+ csv(id, opts) {
1666
+ return this.client.request(
1667
+ "get",
1668
+ `/v1/folders/${encodeURIComponent(id)}/csv`,
1669
+ opts
1670
+ );
1671
+ }
1672
+ /**
1673
+ * PDF of the folder report (every woku, NPS, CSAT and CES tool of the folder
1674
+ * and its subfolders) with a breakdown per type on each native scale.
1675
+ * Returns the file bytes: write them to disk or send them as is.
1676
+ */
1677
+ pdf(id, params, opts) {
1678
+ return this.client.request(
1679
+ "get",
1680
+ `/v1/folders/${encodeURIComponent(id)}/pdf`,
1681
+ {
1682
+ ...opts,
1683
+ headers: { Accept: "application/pdf", ...opts?.headers },
1684
+ query: { ...params, ...opts?.query },
1685
+ binary: true
1686
+ }
1687
+ );
1688
+ }
1689
+ };
1690
+
1691
+ // src/resources/tools.ts
1692
+ var ToolsPage = class {
1693
+ constructor(response, fetchNext, fetchMoreFolders = () => Promise.reject(new RangeError("No more folders"))) {
1694
+ this.fetchNext = fetchNext;
1695
+ this.fetchMoreFolders = fetchMoreFolders;
1696
+ this.folders = response.folders;
1697
+ this.tools = response.tools;
1698
+ this.nextCursor = response.nextCursor;
1699
+ this.foldersNextCursor = response.foldersNextCursor ?? null;
1700
+ this.facets = response.facets;
1701
+ }
1702
+ hasMoreFolders() {
1703
+ return this.foldersNextCursor !== null;
1704
+ }
1705
+ /** The next page of folders ("see more"): a page with those folders and no tools. */
1706
+ getMoreFolders() {
1707
+ if (this.foldersNextCursor === null)
1708
+ throw new RangeError("No more folders");
1709
+ return this.fetchMoreFolders(this.foldersNextCursor);
1710
+ }
1711
+ hasNextPage() {
1712
+ return this.nextCursor !== null;
1713
+ }
1714
+ getNextPage() {
1715
+ if (this.nextCursor === null) throw new RangeError("No next page");
1716
+ return this.fetchNext(this.nextCursor);
1717
+ }
1718
+ async *iterPages() {
1719
+ yield this;
1720
+ if (this.hasNextPage()) yield* (await this.getNextPage()).iterPages();
1721
+ }
1722
+ async *[Symbol.asyncIterator]() {
1723
+ for await (const page of this.iterPages()) {
1724
+ for (const tool of page.tools) yield tool;
1725
+ }
1726
+ }
1727
+ };
1728
+ var Tools = class {
1729
+ constructor(client) {
1730
+ this.client = client;
1731
+ }
1732
+ /**
1733
+ * List one folder level (or search the company). Folders and tools of every
1734
+ * type come together; the first page also carries the folders and facets.
1735
+ */
1736
+ async list(params, opts) {
1737
+ const fetchPage = async (cursor, foldersCursor) => {
1738
+ const response = await this.client.request(
1739
+ "get",
1740
+ "/v1/tools",
1741
+ {
1742
+ ...opts,
1743
+ query: {
1744
+ ...params,
1745
+ types: params?.types?.join(","),
1746
+ ...cursor ? { cursor } : {},
1747
+ ...foldersCursor ? { foldersCursor } : {},
1748
+ ...opts?.query
1749
+ }
1750
+ }
1751
+ );
1752
+ return new ToolsPage(
1753
+ response,
1754
+ fetchPage,
1755
+ (next) => fetchPage(void 0, next)
1756
+ );
1757
+ };
1758
+ return fetchPage();
1759
+ }
1760
+ /**
1761
+ * Headline figures per type (woku stars, NPS score, CSAT satisfied %, CES
1762
+ * mean) for the company or one folder and its subfolders, in a period.
1763
+ * A type that fails reports `{ error: true }`; the others stay valid.
1764
+ */
1765
+ stats(params, opts) {
1766
+ return this.client.request("get", "/v1/tools/stats", {
1767
+ ...opts,
1768
+ query: { ...params, ...opts?.query }
1769
+ });
1770
+ }
1771
+ /**
1772
+ * Move up to 200 items of mixed types (`woku`, `nps`, `csat`, `ces`,
1773
+ * `folder`) into a folder, or to the root with `folderId: null`. Idempotent;
1774
+ * nothing moves if one item or the destination is not found.
1775
+ */
1776
+ move(body, opts) {
1777
+ return this.client.request("post", "/v1/tools/move", {
1778
+ ...opts,
1779
+ body
1780
+ });
1781
+ }
1782
+ };
1783
+
1784
+ // src/resources/journey-folders.ts
1785
+ var JourneyFolders = class {
1786
+ constructor(client) {
1787
+ this.client = client;
1788
+ }
1789
+ /** Whether the organization is on, running, and how much is still without a folder. */
1790
+ status(opts) {
1791
+ return this.client.request(
1792
+ "get",
1793
+ "/v1/journey-folders",
1794
+ opts
1795
+ );
1796
+ }
1797
+ /**
1798
+ * Switch the organization on and run the one-off pass in the background: tools
1799
+ * of existing journeys without a folder move into their moment folder, and
1800
+ * tools journeys create from now on are placed there. Tools that already have
1801
+ * a folder are never touched. Rejects with a conflict (409) while a pass is
1802
+ * already running; poll {@link status} for progress.
1803
+ */
1804
+ organize(opts) {
1805
+ return this.client.request(
1806
+ "post",
1807
+ "/v1/journey-folders/organize",
1808
+ opts
1809
+ );
1810
+ }
1522
1811
  };
1523
1812
 
1524
1813
  // src/woku.ts
@@ -1546,10 +1835,12 @@ var Woku = class {
1546
1835
  this.reports = new Reports(this.client);
1547
1836
  this.company = new Company(this.client);
1548
1837
  this.journeys = new Journeys(this.client);
1549
- this.quarantines = new Quarantines(this.client);
1838
+ this.folders = new Folders(this.client);
1839
+ this.tools = new Tools(this.client);
1840
+ this.journeyFolders = new JourneyFolders(this.client);
1550
1841
  }
1551
1842
  };
1552
1843
 
1553
- export { AuthenticationError, BadRequestError, ConflictError, FollowUps, InternalServerError, Journeys, Media, NotFoundError, Page, PayloadTooLargeError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, Woku, WokuAPIError, WokuClient, WokuConnectionError, WokuError, WokuTimeoutError };
1844
+ export { AuthenticationError, BadRequestError, ConflictError, Folders, FollowUps, InternalServerError, JourneyFolders, Journeys, Media, NotFoundError, Page, PayloadTooLargeError, PermissionDeniedError, RateLimitError, Tools, ToolsPage, UnprocessableEntityError, Woku, WokuAPIError, WokuClient, WokuConnectionError, WokuError, WokuTimeoutError };
1554
1845
  //# sourceMappingURL=index.js.map
1555
1846
  //# sourceMappingURL=index.js.map