eletrotupi / tcc/ commit / bdc1f3a

api: revamp tests

Pedro Lucas Porcellis porcellis@eletrotupi.com · 6 months ago bdc1f3aa45bfff5472ae567a15ca20cc76ec3370 Browse files
Parents 86b8072
Changed files
13
Additions
+1812
Deletions
-1997
api/package-lock.json modified+1501
api/package-lock.json
1 1
{
2 2
  "name": "orbit-api",
3 3
  "version": "0.0.0",
4 4
  "lockfileVersion": 3,
5 5
  "requires": true,
28 28
        "@types/better-sqlite3": "^7.6.13",
29 29
        "@types/express": "^5.0.6",
30 30
        "@types/morgan": "^1.9.10",
31 31
        "@types/node": "^25.5.2",
32 32
        "ava": "^6.4.1",
33 +
        "cross-var": "^1.1.0",
34 +
        "dotenv-cli": "^11.0.0",
33 35
        "prisma": "^7.5.0",
34 36
        "supertest": "^7.1.4",
35 37
        "ts-node": "^10.9.2",
36 38
        "tsc-alias": "^1.8.16",
37 39
        "tsconfig-paths": "^4.2.0",
1544 1546
      "license": "MIT",
1545 1547
      "engines": {
1546 1548
        "node": ">= 6.0.0"
1547 1549
      }
1548 1550
    },
1551 +
    "node_modules/babel-code-frame": {
1552 +
      "version": "6.26.0",
1553 +
      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
1554 +
      "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==",
1555 +
      "dev": true,
1556 +
      "license": "MIT",
1557 +
      "dependencies": {
1558 +
        "chalk": "^1.1.3",
1559 +
        "esutils": "^2.0.2",
1560 +
        "js-tokens": "^3.0.2"
1561 +
      }
1562 +
    },
1563 +
    "node_modules/babel-code-frame/node_modules/ansi-regex": {
1564 +
      "version": "2.1.1",
1565 +
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
1566 +
      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
1567 +
      "dev": true,
1568 +
      "license": "MIT",
1569 +
      "engines": {
1570 +
        "node": ">=0.10.0"
1571 +
      }
1572 +
    },
1573 +
    "node_modules/babel-code-frame/node_modules/ansi-styles": {
1574 +
      "version": "2.2.1",
1575 +
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1576 +
      "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
1577 +
      "dev": true,
1578 +
      "license": "MIT",
1579 +
      "engines": {
1580 +
        "node": ">=0.10.0"
1581 +
      }
1582 +
    },
1583 +
    "node_modules/babel-code-frame/node_modules/chalk": {
1584 +
      "version": "1.1.3",
1585 +
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1586 +
      "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
1587 +
      "dev": true,
1588 +
      "license": "MIT",
1589 +
      "dependencies": {
1590 +
        "ansi-styles": "^2.2.1",
1591 +
        "escape-string-regexp": "^1.0.2",
1592 +
        "has-ansi": "^2.0.0",
1593 +
        "strip-ansi": "^3.0.0",
1594 +
        "supports-color": "^2.0.0"
1595 +
      },
1596 +
      "engines": {
1597 +
        "node": ">=0.10.0"
1598 +
      }
1599 +
    },
1600 +
    "node_modules/babel-code-frame/node_modules/escape-string-regexp": {
1601 +
      "version": "1.0.5",
1602 +
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
1603 +
      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
1604 +
      "dev": true,
1605 +
      "license": "MIT",
1606 +
      "engines": {
1607 +
        "node": ">=0.8.0"
1608 +
      }
1609 +
    },
1610 +
    "node_modules/babel-code-frame/node_modules/strip-ansi": {
1611 +
      "version": "3.0.1",
1612 +
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1613 +
      "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
1614 +
      "dev": true,
1615 +
      "license": "MIT",
1616 +
      "dependencies": {
1617 +
        "ansi-regex": "^2.0.0"
1618 +
      },
1619 +
      "engines": {
1620 +
        "node": ">=0.10.0"
1621 +
      }
1622 +
    },
1623 +
    "node_modules/babel-core": {
1624 +
      "version": "6.26.3",
1625 +
      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
1626 +
      "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
1627 +
      "dev": true,
1628 +
      "license": "MIT",
1629 +
      "dependencies": {
1630 +
        "babel-code-frame": "^6.26.0",
1631 +
        "babel-generator": "^6.26.0",
1632 +
        "babel-helpers": "^6.24.1",
1633 +
        "babel-messages": "^6.23.0",
1634 +
        "babel-register": "^6.26.0",
1635 +
        "babel-runtime": "^6.26.0",
1636 +
        "babel-template": "^6.26.0",
1637 +
        "babel-traverse": "^6.26.0",
1638 +
        "babel-types": "^6.26.0",
1639 +
        "babylon": "^6.18.0",
1640 +
        "convert-source-map": "^1.5.1",
1641 +
        "debug": "^2.6.9",
1642 +
        "json5": "^0.5.1",
1643 +
        "lodash": "^4.17.4",
1644 +
        "minimatch": "^3.0.4",
1645 +
        "path-is-absolute": "^1.0.1",
1646 +
        "private": "^0.1.8",
1647 +
        "slash": "^1.0.0",
1648 +
        "source-map": "^0.5.7"
1649 +
      }
1650 +
    },
1651 +
    "node_modules/babel-core/node_modules/brace-expansion": {
1652 +
      "version": "1.1.13",
1653 +
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
1654 +
      "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
1655 +
      "dev": true,
1656 +
      "license": "MIT",
1657 +
      "dependencies": {
1658 +
        "balanced-match": "^1.0.0",
1659 +
        "concat-map": "0.0.1"
1660 +
      }
1661 +
    },
1662 +
    "node_modules/babel-core/node_modules/debug": {
1663 +
      "version": "2.6.9",
1664 +
      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
1665 +
      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
1666 +
      "dev": true,
1667 +
      "license": "MIT",
1668 +
      "dependencies": {
1669 +
        "ms": "2.0.0"
1670 +
      }
1671 +
    },
1672 +
    "node_modules/babel-core/node_modules/json5": {
1673 +
      "version": "0.5.1",
1674 +
      "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
1675 +
      "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==",
1676 +
      "dev": true,
1677 +
      "license": "MIT",
1678 +
      "bin": {
1679 +
        "json5": "lib/cli.js"
1680 +
      }
1681 +
    },
1682 +
    "node_modules/babel-core/node_modules/minimatch": {
1683 +
      "version": "3.1.5",
1684 +
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
1685 +
      "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
1686 +
      "dev": true,
1687 +
      "license": "ISC",
1688 +
      "dependencies": {
1689 +
        "brace-expansion": "^1.1.7"
1690 +
      },
1691 +
      "engines": {
1692 +
        "node": "*"
1693 +
      }
1694 +
    },
1695 +
    "node_modules/babel-core/node_modules/ms": {
1696 +
      "version": "2.0.0",
1697 +
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1698 +
      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
1699 +
      "dev": true,
1700 +
      "license": "MIT"
1701 +
    },
1702 +
    "node_modules/babel-core/node_modules/slash": {
1703 +
      "version": "1.0.0",
1704 +
      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
1705 +
      "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==",
1706 +
      "dev": true,
1707 +
      "license": "MIT",
1708 +
      "engines": {
1709 +
        "node": ">=0.10.0"
1710 +
      }
1711 +
    },
1712 +
    "node_modules/babel-generator": {
1713 +
      "version": "6.26.1",
1714 +
      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
1715 +
      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
1716 +
      "dev": true,
1717 +
      "license": "MIT",
1718 +
      "dependencies": {
1719 +
        "babel-messages": "^6.23.0",
1720 +
        "babel-runtime": "^6.26.0",
1721 +
        "babel-types": "^6.26.0",
1722 +
        "detect-indent": "^4.0.0",
1723 +
        "jsesc": "^1.3.0",
1724 +
        "lodash": "^4.17.4",
1725 +
        "source-map": "^0.5.7",
1726 +
        "trim-right": "^1.0.1"
1727 +
      }
1728 +
    },
1729 +
    "node_modules/babel-helper-bindify-decorators": {
1730 +
      "version": "6.24.1",
1731 +
      "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
1732 +
      "integrity": "sha512-TYX2QQATKA6Wssp6j7jqlw4QLmABDN1olRdEHndYvBXdaXM5dcx6j5rN0+nd+aVL+Th40fAEYvvw/Xxd/LETuQ==",
1733 +
      "dev": true,
1734 +
      "license": "MIT",
1735 +
      "dependencies": {
1736 +
        "babel-runtime": "^6.22.0",
1737 +
        "babel-traverse": "^6.24.1",
1738 +
        "babel-types": "^6.24.1"
1739 +
      }
1740 +
    },
1741 +
    "node_modules/babel-helper-builder-binary-assignment-operator-visitor": {
1742 +
      "version": "6.24.1",
1743 +
      "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
1744 +
      "integrity": "sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q==",
1745 +
      "dev": true,
1746 +
      "license": "MIT",
1747 +
      "dependencies": {
1748 +
        "babel-helper-explode-assignable-expression": "^6.24.1",
1749 +
        "babel-runtime": "^6.22.0",
1750 +
        "babel-types": "^6.24.1"
1751 +
      }
1752 +
    },
1753 +
    "node_modules/babel-helper-call-delegate": {
1754 +
      "version": "6.24.1",
1755 +
      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
1756 +
      "integrity": "sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ==",
1757 +
      "dev": true,
1758 +
      "license": "MIT",
1759 +
      "dependencies": {
1760 +
        "babel-helper-hoist-variables": "^6.24.1",
1761 +
        "babel-runtime": "^6.22.0",
1762 +
        "babel-traverse": "^6.24.1",
1763 +
        "babel-types": "^6.24.1"
1764 +
      }
1765 +
    },
1766 +
    "node_modules/babel-helper-define-map": {
1767 +
      "version": "6.26.0",
1768 +
      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
1769 +
      "integrity": "sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA==",
1770 +
      "dev": true,
1771 +
      "license": "MIT",
1772 +
      "dependencies": {
1773 +
        "babel-helper-function-name": "^6.24.1",
1774 +
        "babel-runtime": "^6.26.0",
1775 +
        "babel-types": "^6.26.0",
1776 +
        "lodash": "^4.17.4"
1777 +
      }
1778 +
    },
1779 +
    "node_modules/babel-helper-explode-assignable-expression": {
1780 +
      "version": "6.24.1",
1781 +
      "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
1782 +
      "integrity": "sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ==",
1783 +
      "dev": true,
1784 +
      "license": "MIT",
1785 +
      "dependencies": {
1786 +
        "babel-runtime": "^6.22.0",
1787 +
        "babel-traverse": "^6.24.1",
1788 +
        "babel-types": "^6.24.1"
1789 +
      }
1790 +
    },
1791 +
    "node_modules/babel-helper-explode-class": {
1792 +
      "version": "6.24.1",
1793 +
      "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
1794 +
      "integrity": "sha512-SFbWewr0/0U4AiRzsHqwsbOQeLXVa9T1ELdqEa2efcQB5KopTnunAqoj07TuHlN2lfTQNPGO/rJR4FMln5fVcA==",
1795 +
      "dev": true,
1796 +
      "license": "MIT",
1797 +
      "dependencies": {
1798 +
        "babel-helper-bindify-decorators": "^6.24.1",
1799 +
        "babel-runtime": "^6.22.0",
1800 +
        "babel-traverse": "^6.24.1",
1801 +
        "babel-types": "^6.24.1"
1802 +
      }
1803 +
    },
1804 +
    "node_modules/babel-helper-function-name": {
1805 +
      "version": "6.24.1",
1806 +
      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
1807 +
      "integrity": "sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q==",
1808 +
      "dev": true,
1809 +
      "license": "MIT",
1810 +
      "dependencies": {
1811 +
        "babel-helper-get-function-arity": "^6.24.1",
1812 +
        "babel-runtime": "^6.22.0",
1813 +
        "babel-template": "^6.24.1",
1814 +
        "babel-traverse": "^6.24.1",
1815 +
        "babel-types": "^6.24.1"
1816 +
      }
1817 +
    },
1818 +
    "node_modules/babel-helper-get-function-arity": {
1819 +
      "version": "6.24.1",
1820 +
      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
1821 +
      "integrity": "sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng==",
1822 +
      "dev": true,
1823 +
      "license": "MIT",
1824 +
      "dependencies": {
1825 +
        "babel-runtime": "^6.22.0",
1826 +
        "babel-types": "^6.24.1"
1827 +
      }
1828 +
    },
1829 +
    "node_modules/babel-helper-hoist-variables": {
1830 +
      "version": "6.24.1",
1831 +
      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
1832 +
      "integrity": "sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw==",
1833 +
      "dev": true,
1834 +
      "license": "MIT",
1835 +
      "dependencies": {
1836 +
        "babel-runtime": "^6.22.0",
1837 +
        "babel-types": "^6.24.1"
1838 +
      }
1839 +
    },
1840 +
    "node_modules/babel-helper-optimise-call-expression": {
1841 +
      "version": "6.24.1",
1842 +
      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
1843 +
      "integrity": "sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA==",
1844 +
      "dev": true,
1845 +
      "license": "MIT",
1846 +
      "dependencies": {
1847 +
        "babel-runtime": "^6.22.0",
1848 +
        "babel-types": "^6.24.1"
1849 +
      }
1850 +
    },
1851 +
    "node_modules/babel-helper-regex": {
1852 +
      "version": "6.26.0",
1853 +
      "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
1854 +
      "integrity": "sha512-VlPiWmqmGJp0x0oK27Out1D+71nVVCTSdlbhIVoaBAj2lUgrNjBCRR9+llO4lTSb2O4r7PJg+RobRkhBrf6ofg==",
1855 +
      "dev": true,
1856 +
      "license": "MIT",
1857 +
      "dependencies": {
1858 +
        "babel-runtime": "^6.26.0",
1859 +
        "babel-types": "^6.26.0",
1860 +
        "lodash": "^4.17.4"
1861 +
      }
1862 +
    },
1863 +
    "node_modules/babel-helper-remap-async-to-generator": {
1864 +
      "version": "6.24.1",
1865 +
      "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
1866 +
      "integrity": "sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg==",
1867 +
      "dev": true,
1868 +
      "license": "MIT",
1869 +
      "dependencies": {
1870 +
        "babel-helper-function-name": "^6.24.1",
1871 +
        "babel-runtime": "^6.22.0",
1872 +
        "babel-template": "^6.24.1",
1873 +
        "babel-traverse": "^6.24.1",
1874 +
        "babel-types": "^6.24.1"
1875 +
      }
1876 +
    },
1877 +
    "node_modules/babel-helper-replace-supers": {
1878 +
      "version": "6.24.1",
1879 +
      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
1880 +
      "integrity": "sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw==",
1881 +
      "dev": true,
1882 +
      "license": "MIT",
1883 +
      "dependencies": {
1884 +
        "babel-helper-optimise-call-expression": "^6.24.1",
1885 +
        "babel-messages": "^6.23.0",
1886 +
        "babel-runtime": "^6.22.0",
1887 +
        "babel-template": "^6.24.1",
1888 +
        "babel-traverse": "^6.24.1",
1889 +
        "babel-types": "^6.24.1"
1890 +
      }
1891 +
    },
1892 +
    "node_modules/babel-helpers": {
1893 +
      "version": "6.24.1",
1894 +
      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
1895 +
      "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==",
1896 +
      "dev": true,
1897 +
      "license": "MIT",
1898 +
      "dependencies": {
1899 +
        "babel-runtime": "^6.22.0",
1900 +
        "babel-template": "^6.24.1"
1901 +
      }
1902 +
    },
1903 +
    "node_modules/babel-messages": {
1904 +
      "version": "6.23.0",
1905 +
      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
1906 +
      "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==",
1907 +
      "dev": true,
1908 +
      "license": "MIT",
1909 +
      "dependencies": {
1910 +
        "babel-runtime": "^6.22.0"
1911 +
      }
1912 +
    },
1913 +
    "node_modules/babel-plugin-check-es2015-constants": {
1914 +
      "version": "6.22.0",
1915 +
      "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
1916 +
      "integrity": "sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA==",
1917 +
      "dev": true,
1918 +
      "license": "MIT",
1919 +
      "dependencies": {
1920 +
        "babel-runtime": "^6.22.0"
1921 +
      }
1922 +
    },
1923 +
    "node_modules/babel-plugin-syntax-async-functions": {
1924 +
      "version": "6.13.0",
1925 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
1926 +
      "integrity": "sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw==",
1927 +
      "dev": true,
1928 +
      "license": "MIT"
1929 +
    },
1930 +
    "node_modules/babel-plugin-syntax-async-generators": {
1931 +
      "version": "6.13.0",
1932 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
1933 +
      "integrity": "sha512-EbciFN5Jb9iqU9bqaLmmFLx2G8pAUsvpWJ6OzOWBNrSY9qTohXj+7YfZx6Ug1Qqh7tCb1EA7Jvn9bMC1HBiucg==",
1934 +
      "dev": true,
1935 +
      "license": "MIT"
1936 +
    },
1937 +
    "node_modules/babel-plugin-syntax-class-constructor-call": {
1938 +
      "version": "6.18.0",
1939 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz",
1940 +
      "integrity": "sha512-EEuBcXz/wZ81Jaac0LnMHtD4Mfz9XWn2oH2Xj+CHwz2SZWUqqdtR2BgWPSdTGMmxN/5KLSh4PImt9+9ZedDarA==",
1941 +
      "dev": true,
1942 +
      "license": "MIT"
1943 +
    },
1944 +
    "node_modules/babel-plugin-syntax-class-properties": {
1945 +
      "version": "6.13.0",
1946 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
1947 +
      "integrity": "sha512-chI3Rt9T1AbrQD1s+vxw3KcwC9yHtF621/MacuItITfZX344uhQoANjpoSJZleAmW2tjlolqB/f+h7jIqXa7pA==",
1948 +
      "dev": true,
1949 +
      "license": "MIT"
1950 +
    },
1951 +
    "node_modules/babel-plugin-syntax-decorators": {
1952 +
      "version": "6.13.0",
1953 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
1954 +
      "integrity": "sha512-AWj19x2aDm8qFQ5O2JcD6pwJDW1YdcnO+1b81t7gxrGjz5VHiUqeYWAR4h7zueWMalRelrQDXprv2FrY1dbpbw==",
1955 +
      "dev": true,
1956 +
      "license": "MIT"
1957 +
    },
1958 +
    "node_modules/babel-plugin-syntax-do-expressions": {
1959 +
      "version": "6.13.0",
1960 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz",
1961 +
      "integrity": "sha512-HD/5qJB9oSXzl0caxM+aRD7ENICXqcc3Up/8toDQk7zNIDE7TzsqtxC5f4t9Rwhu2Ya8l9l4j6b3vOsy+a6qxg==",
1962 +
      "dev": true,
1963 +
      "license": "MIT"
1964 +
    },
1965 +
    "node_modules/babel-plugin-syntax-dynamic-import": {
1966 +
      "version": "6.18.0",
1967 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
1968 +
      "integrity": "sha512-MioUE+LfjCEz65Wf7Z/Rm4XCP5k2c+TbMd2Z2JKc7U9uwjBhAfNPE48KC4GTGKhppMeYVepwDBNO/nGY6NYHBA==",
1969 +
      "dev": true,
1970 +
      "license": "MIT"
1971 +
    },
1972 +
    "node_modules/babel-plugin-syntax-exponentiation-operator": {
1973 +
      "version": "6.13.0",
1974 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
1975 +
      "integrity": "sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==",
1976 +
      "dev": true,
1977 +
      "license": "MIT"
1978 +
    },
1979 +
    "node_modules/babel-plugin-syntax-export-extensions": {
1980 +
      "version": "6.13.0",
1981 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz",
1982 +
      "integrity": "sha512-Eo0rcRaIDMld/W6mVhePiudIuLW+Cr/8eveW3mBREfZORScZgx4rh6BAPyvzdEc/JZvQ+LkC80t0VGFs6FX+lg==",
1983 +
      "dev": true,
1984 +
      "license": "MIT"
1985 +
    },
1986 +
    "node_modules/babel-plugin-syntax-function-bind": {
1987 +
      "version": "6.13.0",
1988 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz",
1989 +
      "integrity": "sha512-m8yMoh9LIiNyeLdQs5I9G+3YXo4nqVsKQkk7YplrG4qAFbNi9hkZlow8HDHxhH9QOVFPHmy8+03NzRCdyChIKw==",
1990 +
      "dev": true,
1991 +
      "license": "MIT"
1992 +
    },
1993 +
    "node_modules/babel-plugin-syntax-object-rest-spread": {
1994 +
      "version": "6.13.0",
1995 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
1996 +
      "integrity": "sha512-C4Aq+GaAj83pRQ0EFgTvw5YO6T3Qz2KGrNRwIj9mSoNHVvdZY4KO2uA6HNtNXCw993iSZnckY1aLW8nOi8i4+w==",
1997 +
      "dev": true,
1998 +
      "license": "MIT"
1999 +
    },
2000 +
    "node_modules/babel-plugin-syntax-trailing-function-commas": {
2001 +
      "version": "6.22.0",
2002 +
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
2003 +
      "integrity": "sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==",
2004 +
      "dev": true,
2005 +
      "license": "MIT"
2006 +
    },
2007 +
    "node_modules/babel-plugin-transform-async-generator-functions": {
2008 +
      "version": "6.24.1",
2009 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
2010 +
      "integrity": "sha512-uT7eovUxtXe8Q2ufcjRuJIOL0hg6VAUJhiWJBLxH/evYAw+aqoJLcYTR8hqx13iOx/FfbCMHgBmXWZjukbkyPg==",
2011 +
      "dev": true,
2012 +
      "license": "MIT",
2013 +
      "dependencies": {
2014 +
        "babel-helper-remap-async-to-generator": "^6.24.1",
2015 +
        "babel-plugin-syntax-async-generators": "^6.5.0",
2016 +
        "babel-runtime": "^6.22.0"
2017 +
      }
2018 +
    },
2019 +
    "node_modules/babel-plugin-transform-async-to-generator": {
2020 +
      "version": "6.24.1",
2021 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
2022 +
      "integrity": "sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw==",
2023 +
      "dev": true,
2024 +
      "license": "MIT",
2025 +
      "dependencies": {
2026 +
        "babel-helper-remap-async-to-generator": "^6.24.1",
2027 +
        "babel-plugin-syntax-async-functions": "^6.8.0",
2028 +
        "babel-runtime": "^6.22.0"
2029 +
      }
2030 +
    },
2031 +
    "node_modules/babel-plugin-transform-class-constructor-call": {
2032 +
      "version": "6.24.1",
2033 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz",
2034 +
      "integrity": "sha512-RvYukT1Nh7njz8P8326ztpQUGCKwmjgu6aRIx1lkvylWITYcskg29vy1Kp8WXIq7FvhXsz0Crf2kS94bjB690A==",
2035 +
      "dev": true,
2036 +
      "license": "MIT",
2037 +
      "dependencies": {
2038 +
        "babel-plugin-syntax-class-constructor-call": "^6.18.0",
2039 +
        "babel-runtime": "^6.22.0",
2040 +
        "babel-template": "^6.24.1"
2041 +
      }
2042 +
    },
2043 +
    "node_modules/babel-plugin-transform-class-properties": {
2044 +
      "version": "6.24.1",
2045 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
2046 +
      "integrity": "sha512-n4jtBA3OYBdvG5PRMKsMXJXHfLYw/ZOmtxCLOOwz6Ro5XlrColkStLnz1AS1L2yfPA9BKJ1ZNlmVCLjAL9DSIg==",
2047 +
      "dev": true,
2048 +
      "license": "MIT",
2049 +
      "dependencies": {
2050 +
        "babel-helper-function-name": "^6.24.1",
2051 +
        "babel-plugin-syntax-class-properties": "^6.8.0",
2052 +
        "babel-runtime": "^6.22.0",
2053 +
        "babel-template": "^6.24.1"
2054 +
      }
2055 +
    },
2056 +
    "node_modules/babel-plugin-transform-decorators": {
2057 +
      "version": "6.24.1",
2058 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
2059 +
      "integrity": "sha512-skQ2CImwDkCHu0mkWvCOlBCpBIHW4/49IZWVwV4A/EnWjL9bB6UBvLyMNe3Td5XDStSZNhe69j4bfEW8dvUbew==",
2060 +
      "dev": true,
2061 +
      "license": "MIT",
2062 +
      "dependencies": {
2063 +
        "babel-helper-explode-class": "^6.24.1",
2064 +
        "babel-plugin-syntax-decorators": "^6.13.0",
2065 +
        "babel-runtime": "^6.22.0",
2066 +
        "babel-template": "^6.24.1",
2067 +
        "babel-types": "^6.24.1"
2068 +
      }
2069 +
    },
2070 +
    "node_modules/babel-plugin-transform-do-expressions": {
2071 +
      "version": "6.22.0",
2072 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz",
2073 +
      "integrity": "sha512-yQwYqYg+Tnj1InA8W1rsItsZVhkv1Euc4KVua9ledtPz5PDWYz7LVyy6rDBpVYUWFZj5k6GUm3YZpCbIm8Tqew==",
2074 +
      "dev": true,
2075 +
      "license": "MIT",
2076 +
      "dependencies": {
2077 +
        "babel-plugin-syntax-do-expressions": "^6.8.0",
2078 +
        "babel-runtime": "^6.22.0"
2079 +
      }
2080 +
    },
2081 +
    "node_modules/babel-plugin-transform-es2015-arrow-functions": {
2082 +
      "version": "6.22.0",
2083 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
2084 +
      "integrity": "sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg==",
2085 +
      "dev": true,
2086 +
      "license": "MIT",
2087 +
      "dependencies": {
2088 +
        "babel-runtime": "^6.22.0"
2089 +
      }
2090 +
    },
2091 +
    "node_modules/babel-plugin-transform-es2015-block-scoped-functions": {
2092 +
      "version": "6.22.0",
2093 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
2094 +
      "integrity": "sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A==",
2095 +
      "dev": true,
2096 +
      "license": "MIT",
2097 +
      "dependencies": {
2098 +
        "babel-runtime": "^6.22.0"
2099 +
      }
2100 +
    },
2101 +
    "node_modules/babel-plugin-transform-es2015-block-scoping": {
2102 +
      "version": "6.26.0",
2103 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
2104 +
      "integrity": "sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==",
2105 +
      "dev": true,
2106 +
      "license": "MIT",
2107 +
      "dependencies": {
2108 +
        "babel-runtime": "^6.26.0",
2109 +
        "babel-template": "^6.26.0",
2110 +
        "babel-traverse": "^6.26.0",
2111 +
        "babel-types": "^6.26.0",
2112 +
        "lodash": "^4.17.4"
2113 +
      }
2114 +
    },
2115 +
    "node_modules/babel-plugin-transform-es2015-classes": {
2116 +
      "version": "6.24.1",
2117 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
2118 +
      "integrity": "sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag==",
2119 +
      "dev": true,
2120 +
      "license": "MIT",
2121 +
      "dependencies": {
2122 +
        "babel-helper-define-map": "^6.24.1",
2123 +
        "babel-helper-function-name": "^6.24.1",
2124 +
        "babel-helper-optimise-call-expression": "^6.24.1",
2125 +
        "babel-helper-replace-supers": "^6.24.1",
2126 +
        "babel-messages": "^6.23.0",
2127 +
        "babel-runtime": "^6.22.0",
2128 +
        "babel-template": "^6.24.1",
2129 +
        "babel-traverse": "^6.24.1",
2130 +
        "babel-types": "^6.24.1"
2131 +
      }
2132 +
    },
2133 +
    "node_modules/babel-plugin-transform-es2015-computed-properties": {
2134 +
      "version": "6.24.1",
2135 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
2136 +
      "integrity": "sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw==",
2137 +
      "dev": true,
2138 +
      "license": "MIT",
2139 +
      "dependencies": {
2140 +
        "babel-runtime": "^6.22.0",
2141 +
        "babel-template": "^6.24.1"
2142 +
      }
2143 +
    },
2144 +
    "node_modules/babel-plugin-transform-es2015-destructuring": {
2145 +
      "version": "6.23.0",
2146 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
2147 +
      "integrity": "sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA==",
2148 +
      "dev": true,
2149 +
      "license": "MIT",
2150 +
      "dependencies": {
2151 +
        "babel-runtime": "^6.22.0"
2152 +
      }
2153 +
    },
2154 +
    "node_modules/babel-plugin-transform-es2015-duplicate-keys": {
2155 +
      "version": "6.24.1",
2156 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
2157 +
      "integrity": "sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug==",
2158 +
      "dev": true,
2159 +
      "license": "MIT",
2160 +
      "dependencies": {
2161 +
        "babel-runtime": "^6.22.0",
2162 +
        "babel-types": "^6.24.1"
2163 +
      }
2164 +
    },
2165 +
    "node_modules/babel-plugin-transform-es2015-for-of": {
2166 +
      "version": "6.23.0",
2167 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
2168 +
      "integrity": "sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw==",
2169 +
      "dev": true,
2170 +
      "license": "MIT",
2171 +
      "dependencies": {
2172 +
        "babel-runtime": "^6.22.0"
2173 +
      }
2174 +
    },
2175 +
    "node_modules/babel-plugin-transform-es2015-function-name": {
2176 +
      "version": "6.24.1",
2177 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
2178 +
      "integrity": "sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg==",
2179 +
      "dev": true,
2180 +
      "license": "MIT",
2181 +
      "dependencies": {
2182 +
        "babel-helper-function-name": "^6.24.1",
2183 +
        "babel-runtime": "^6.22.0",
2184 +
        "babel-types": "^6.24.1"
2185 +
      }
2186 +
    },
2187 +
    "node_modules/babel-plugin-transform-es2015-literals": {
2188 +
      "version": "6.22.0",
2189 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
2190 +
      "integrity": "sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ==",
2191 +
      "dev": true,
2192 +
      "license": "MIT",
2193 +
      "dependencies": {
2194 +
        "babel-runtime": "^6.22.0"
2195 +
      }
2196 +
    },
2197 +
    "node_modules/babel-plugin-transform-es2015-modules-amd": {
2198 +
      "version": "6.24.1",
2199 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
2200 +
      "integrity": "sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA==",
2201 +
      "dev": true,
2202 +
      "license": "MIT",
2203 +
      "dependencies": {
2204 +
        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
2205 +
        "babel-runtime": "^6.22.0",
2206 +
        "babel-template": "^6.24.1"
2207 +
      }
2208 +
    },
2209 +
    "node_modules/babel-plugin-transform-es2015-modules-commonjs": {
2210 +
      "version": "6.26.2",
2211 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
2212 +
      "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
2213 +
      "dev": true,
2214 +
      "license": "MIT",
2215 +
      "dependencies": {
2216 +
        "babel-plugin-transform-strict-mode": "^6.24.1",
2217 +
        "babel-runtime": "^6.26.0",
2218 +
        "babel-template": "^6.26.0",
2219 +
        "babel-types": "^6.26.0"
2220 +
      }
2221 +
    },
2222 +
    "node_modules/babel-plugin-transform-es2015-modules-systemjs": {
2223 +
      "version": "6.24.1",
2224 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
2225 +
      "integrity": "sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg==",
2226 +
      "dev": true,
2227 +
      "license": "MIT",
2228 +
      "dependencies": {
2229 +
        "babel-helper-hoist-variables": "^6.24.1",
2230 +
        "babel-runtime": "^6.22.0",
2231 +
        "babel-template": "^6.24.1"
2232 +
      }
2233 +
    },
2234 +
    "node_modules/babel-plugin-transform-es2015-modules-umd": {
2235 +
      "version": "6.24.1",
2236 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
2237 +
      "integrity": "sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw==",
2238 +
      "dev": true,
2239 +
      "license": "MIT",
2240 +
      "dependencies": {
2241 +
        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
2242 +
        "babel-runtime": "^6.22.0",
2243 +
        "babel-template": "^6.24.1"
2244 +
      }
2245 +
    },
2246 +
    "node_modules/babel-plugin-transform-es2015-object-super": {
2247 +
      "version": "6.24.1",
2248 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
2249 +
      "integrity": "sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA==",
2250 +
      "dev": true,
2251 +
      "license": "MIT",
2252 +
      "dependencies": {
2253 +
        "babel-helper-replace-supers": "^6.24.1",
2254 +
        "babel-runtime": "^6.22.0"
2255 +
      }
2256 +
    },
2257 +
    "node_modules/babel-plugin-transform-es2015-parameters": {
2258 +
      "version": "6.24.1",
2259 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
2260 +
      "integrity": "sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ==",
2261 +
      "dev": true,
2262 +
      "license": "MIT",
2263 +
      "dependencies": {
2264 +
        "babel-helper-call-delegate": "^6.24.1",
2265 +
        "babel-helper-get-function-arity": "^6.24.1",
2266 +
        "babel-runtime": "^6.22.0",
2267 +
        "babel-template": "^6.24.1",
2268 +
        "babel-traverse": "^6.24.1",
2269 +
        "babel-types": "^6.24.1"
2270 +
      }
2271 +
    },
2272 +
    "node_modules/babel-plugin-transform-es2015-shorthand-properties": {
2273 +
      "version": "6.24.1",
2274 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
2275 +
      "integrity": "sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw==",
2276 +
      "dev": true,
2277 +
      "license": "MIT",
2278 +
      "dependencies": {
2279 +
        "babel-runtime": "^6.22.0",
2280 +
        "babel-types": "^6.24.1"
2281 +
      }
2282 +
    },
2283 +
    "node_modules/babel-plugin-transform-es2015-spread": {
2284 +
      "version": "6.22.0",
2285 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
2286 +
      "integrity": "sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg==",
2287 +
      "dev": true,
2288 +
      "license": "MIT",
2289 +
      "dependencies": {
2290 +
        "babel-runtime": "^6.22.0"
2291 +
      }
2292 +
    },
2293 +
    "node_modules/babel-plugin-transform-es2015-sticky-regex": {
2294 +
      "version": "6.24.1",
2295 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
2296 +
      "integrity": "sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ==",
2297 +
      "dev": true,
2298 +
      "license": "MIT",
2299 +
      "dependencies": {
2300 +
        "babel-helper-regex": "^6.24.1",
2301 +
        "babel-runtime": "^6.22.0",
2302 +
        "babel-types": "^6.24.1"
2303 +
      }
2304 +
    },
2305 +
    "node_modules/babel-plugin-transform-es2015-template-literals": {
2306 +
      "version": "6.22.0",
2307 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
2308 +
      "integrity": "sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg==",
2309 +
      "dev": true,
2310 +
      "license": "MIT",
2311 +
      "dependencies": {
2312 +
        "babel-runtime": "^6.22.0"
2313 +
      }
2314 +
    },
2315 +
    "node_modules/babel-plugin-transform-es2015-typeof-symbol": {
2316 +
      "version": "6.23.0",
2317 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
2318 +
      "integrity": "sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw==",
2319 +
      "dev": true,
2320 +
      "license": "MIT",
2321 +
      "dependencies": {
2322 +
        "babel-runtime": "^6.22.0"
2323 +
      }
2324 +
    },
2325 +
    "node_modules/babel-plugin-transform-es2015-unicode-regex": {
2326 +
      "version": "6.24.1",
2327 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
2328 +
      "integrity": "sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ==",
2329 +
      "dev": true,
2330 +
      "license": "MIT",
2331 +
      "dependencies": {
2332 +
        "babel-helper-regex": "^6.24.1",
2333 +
        "babel-runtime": "^6.22.0",
2334 +
        "regexpu-core": "^2.0.0"
2335 +
      }
2336 +
    },
2337 +
    "node_modules/babel-plugin-transform-exponentiation-operator": {
2338 +
      "version": "6.24.1",
2339 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
2340 +
      "integrity": "sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ==",
2341 +
      "dev": true,
2342 +
      "license": "MIT",
2343 +
      "dependencies": {
2344 +
        "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
2345 +
        "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
2346 +
        "babel-runtime": "^6.22.0"
2347 +
      }
2348 +
    },
2349 +
    "node_modules/babel-plugin-transform-export-extensions": {
2350 +
      "version": "6.22.0",
2351 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz",
2352 +
      "integrity": "sha512-mtzELzINaYqdVglyZrDDVwkcFRuE7s6QUFWXxwffKAHB/NkfbJ2NJSytugB43ytIC8UVt30Ereyx+7gNyTkDLg==",
2353 +
      "dev": true,
2354 +
      "license": "MIT",
2355 +
      "dependencies": {
2356 +
        "babel-plugin-syntax-export-extensions": "^6.8.0",
2357 +
        "babel-runtime": "^6.22.0"
2358 +
      }
2359 +
    },
2360 +
    "node_modules/babel-plugin-transform-function-bind": {
2361 +
      "version": "6.22.0",
2362 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz",
2363 +
      "integrity": "sha512-9Ec4KYf1GurT39mlUjDSlN7HWSlB3u3mWRMogQbb+Y88lO0ZM3rJ0ADhPnQwWK9TbO6e/4E+Et1rrfGY9mFimA==",
2364 +
      "dev": true,
2365 +
      "license": "MIT",
2366 +
      "dependencies": {
2367 +
        "babel-plugin-syntax-function-bind": "^6.8.0",
2368 +
        "babel-runtime": "^6.22.0"
2369 +
      }
2370 +
    },
2371 +
    "node_modules/babel-plugin-transform-object-rest-spread": {
2372 +
      "version": "6.26.0",
2373 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
2374 +
      "integrity": "sha512-ocgA9VJvyxwt+qJB0ncxV8kb/CjfTcECUY4tQ5VT7nP6Aohzobm8CDFaQ5FHdvZQzLmf0sgDxB8iRXZXxwZcyA==",
2375 +
      "dev": true,
2376 +
      "license": "MIT",
2377 +
      "dependencies": {
2378 +
        "babel-plugin-syntax-object-rest-spread": "^6.8.0",
2379 +
        "babel-runtime": "^6.26.0"
2380 +
      }
2381 +
    },
2382 +
    "node_modules/babel-plugin-transform-regenerator": {
2383 +
      "version": "6.26.0",
2384 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
2385 +
      "integrity": "sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg==",
2386 +
      "dev": true,
2387 +
      "license": "MIT",
2388 +
      "dependencies": {
2389 +
        "regenerator-transform": "^0.10.0"
2390 +
      }
2391 +
    },
2392 +
    "node_modules/babel-plugin-transform-strict-mode": {
2393 +
      "version": "6.24.1",
2394 +
      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
2395 +
      "integrity": "sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw==",
2396 +
      "dev": true,
2397 +
      "license": "MIT",
2398 +
      "dependencies": {
2399 +
        "babel-runtime": "^6.22.0",
2400 +
        "babel-types": "^6.24.1"
2401 +
      }
2402 +
    },
2403 +
    "node_modules/babel-preset-es2015": {
2404 +
      "version": "6.24.1",
2405 +
      "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
2406 +
      "integrity": "sha512-XfwUqG1Ry6R43m4Wfob+vHbIVBIqTg/TJY4Snku1iIzeH7mUnwHA8Vagmv+ZQbPwhS8HgsdQvy28Py3k5zpoFQ==",
2407 +
      "deprecated": "🙌  Thanks for using Babel: we recommend using babel-preset-env now: please read https://babeljs.io/env to update!",
2408 +
      "dev": true,
2409 +
      "license": "MIT",
2410 +
      "dependencies": {
2411 +
        "babel-plugin-check-es2015-constants": "^6.22.0",
2412 +
        "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
2413 +
        "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
2414 +
        "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
2415 +
        "babel-plugin-transform-es2015-classes": "^6.24.1",
2416 +
        "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
2417 +
        "babel-plugin-transform-es2015-destructuring": "^6.22.0",
2418 +
        "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
2419 +
        "babel-plugin-transform-es2015-for-of": "^6.22.0",
2420 +
        "babel-plugin-transform-es2015-function-name": "^6.24.1",
2421 +
        "babel-plugin-transform-es2015-literals": "^6.22.0",
2422 +
        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
2423 +
        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
2424 +
        "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
2425 +
        "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
2426 +
        "babel-plugin-transform-es2015-object-super": "^6.24.1",
2427 +
        "babel-plugin-transform-es2015-parameters": "^6.24.1",
2428 +
        "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
2429 +
        "babel-plugin-transform-es2015-spread": "^6.22.0",
2430 +
        "babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
2431 +
        "babel-plugin-transform-es2015-template-literals": "^6.22.0",
2432 +
        "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
2433 +
        "babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
2434 +
        "babel-plugin-transform-regenerator": "^6.24.1"
2435 +
      }
2436 +
    },
2437 +
    "node_modules/babel-preset-stage-0": {
2438 +
      "version": "6.24.1",
2439 +
      "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz",
2440 +
      "integrity": "sha512-MJD+xBbpsApbKlzAX0sOBF+VeFaUmv5s8FSOO7SSZpes1QgphCjq/UIGRFWSmQ/0i5bqQjLGCTXGGXqcLQ9JDA==",
2441 +
      "dev": true,
2442 +
      "license": "MIT",
2443 +
      "dependencies": {
2444 +
        "babel-plugin-transform-do-expressions": "^6.22.0",
2445 +
        "babel-plugin-transform-function-bind": "^6.22.0",
2446 +
        "babel-preset-stage-1": "^6.24.1"
2447 +
      }
2448 +
    },
2449 +
    "node_modules/babel-preset-stage-1": {
2450 +
      "version": "6.24.1",
2451 +
      "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz",
2452 +
      "integrity": "sha512-rn+UOcd7BHDniq1SVxv2/AVVSVI1NK+hfS0I/iR6m6KbOi/aeBRcqBilqO73pd9VUpRXF2HFtlDuC9F2BEQqmg==",
2453 +
      "dev": true,
2454 +
      "license": "MIT",
2455 +
      "dependencies": {
2456 +
        "babel-plugin-transform-class-constructor-call": "^6.24.1",
2457 +
        "babel-plugin-transform-export-extensions": "^6.22.0",
2458 +
        "babel-preset-stage-2": "^6.24.1"
2459 +
      }
2460 +
    },
2461 +
    "node_modules/babel-preset-stage-2": {
2462 +
      "version": "6.24.1",
2463 +
      "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
2464 +
      "integrity": "sha512-9F+nquz+37PrlTSBdpeQBKnQfAMNBnryXw+m4qBh35FNbJPfzZz+sjN2G5Uf1CRedU9PH7fJkTbYijxmkLX8Og==",
2465 +
      "dev": true,
2466 +
      "license": "MIT",
2467 +
      "dependencies": {
2468 +
        "babel-plugin-syntax-dynamic-import": "^6.18.0",
2469 +
        "babel-plugin-transform-class-properties": "^6.24.1",
2470 +
        "babel-plugin-transform-decorators": "^6.24.1",
2471 +
        "babel-preset-stage-3": "^6.24.1"
2472 +
      }
2473 +
    },
2474 +
    "node_modules/babel-preset-stage-3": {
2475 +
      "version": "6.24.1",
2476 +
      "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
2477 +
      "integrity": "sha512-eCbEOF8uN0KypFXJmZXn2sTk7bPV9uM5xov7G/7BM08TbQEObsVs0cEWfy6NQySlfk7JBi/t+XJP1JkruYfthA==",
2478 +
      "dev": true,
2479 +
      "license": "MIT",
2480 +
      "dependencies": {
2481 +
        "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
2482 +
        "babel-plugin-transform-async-generator-functions": "^6.24.1",
2483 +
        "babel-plugin-transform-async-to-generator": "^6.24.1",
2484 +
        "babel-plugin-transform-exponentiation-operator": "^6.24.1",
2485 +
        "babel-plugin-transform-object-rest-spread": "^6.22.0"
2486 +
      }
2487 +
    },
2488 +
    "node_modules/babel-register": {
2489 +
      "version": "6.26.0",
2490 +
      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
2491 +
      "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==",
2492 +
      "dev": true,
2493 +
      "license": "MIT",
2494 +
      "dependencies": {
2495 +
        "babel-core": "^6.26.0",
2496 +
        "babel-runtime": "^6.26.0",
2497 +
        "core-js": "^2.5.0",
2498 +
        "home-or-tmp": "^2.0.0",
2499 +
        "lodash": "^4.17.4",
2500 +
        "mkdirp": "^0.5.1",
2501 +
        "source-map-support": "^0.4.15"
2502 +
      }
2503 +
    },
2504 +
    "node_modules/babel-runtime": {
2505 +
      "version": "6.26.0",
2506 +
      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
2507 +
      "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
2508 +
      "dev": true,
2509 +
      "license": "MIT",
2510 +
      "dependencies": {
2511 +
        "core-js": "^2.4.0",
2512 +
        "regenerator-runtime": "^0.11.0"
2513 +
      }
2514 +
    },
2515 +
    "node_modules/babel-template": {
2516 +
      "version": "6.26.0",
2517 +
      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
2518 +
      "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==",
2519 +
      "dev": true,
2520 +
      "license": "MIT",
2521 +
      "dependencies": {
2522 +
        "babel-runtime": "^6.26.0",
2523 +
        "babel-traverse": "^6.26.0",
2524 +
        "babel-types": "^6.26.0",
2525 +
        "babylon": "^6.18.0",
2526 +
        "lodash": "^4.17.4"
2527 +
      }
2528 +
    },
2529 +
    "node_modules/babel-traverse": {
2530 +
      "version": "6.26.0",
2531 +
      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
2532 +
      "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==",
2533 +
      "dev": true,
2534 +
      "license": "MIT",
2535 +
      "dependencies": {
2536 +
        "babel-code-frame": "^6.26.0",
2537 +
        "babel-messages": "^6.23.0",
2538 +
        "babel-runtime": "^6.26.0",
2539 +
        "babel-types": "^6.26.0",
2540 +
        "babylon": "^6.18.0",
2541 +
        "debug": "^2.6.8",
2542 +
        "globals": "^9.18.0",
2543 +
        "invariant": "^2.2.2",
2544 +
        "lodash": "^4.17.4"
2545 +
      }
2546 +
    },
2547 +
    "node_modules/babel-traverse/node_modules/debug": {
2548 +
      "version": "2.6.9",
2549 +
      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
2550 +
      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
2551 +
      "dev": true,
2552 +
      "license": "MIT",
2553 +
      "dependencies": {
2554 +
        "ms": "2.0.0"
2555 +
      }
2556 +
    },
2557 +
    "node_modules/babel-traverse/node_modules/ms": {
2558 +
      "version": "2.0.0",
2559 +
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
2560 +
      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
2561 +
      "dev": true,
2562 +
      "license": "MIT"
2563 +
    },
2564 +
    "node_modules/babel-types": {
2565 +
      "version": "6.26.0",
2566 +
      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
2567 +
      "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==",
2568 +
      "dev": true,
2569 +
      "license": "MIT",
2570 +
      "dependencies": {
2571 +
        "babel-runtime": "^6.26.0",
2572 +
        "esutils": "^2.0.2",
2573 +
        "lodash": "^4.17.4",
2574 +
        "to-fast-properties": "^1.0.3"
2575 +
      }
2576 +
    },
2577 +
    "node_modules/babylon": {
2578 +
      "version": "6.18.0",
2579 +
      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
2580 +
      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
2581 +
      "dev": true,
2582 +
      "license": "MIT",
2583 +
      "bin": {
2584 +
        "babylon": "bin/babylon.js"
2585 +
      }
2586 +
    },
1549 2587
    "node_modules/balanced-match": {
1550 2588
      "version": "1.0.2",
1551 2589
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1552 2590
      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1553 2591
      "dev": true,
2106 3144
      "license": "MIT",
2107 3145
      "funding": {
2108 3146
        "url": "https://github.com/sponsors/sindresorhus"
2109 3147
      }
2110 3148
    },
3149 +
    "node_modules/concat-map": {
3150 +
      "version": "0.0.1",
3151 +
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
3152 +
      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
3153 +
      "dev": true,
3154 +
      "license": "MIT"
3155 +
    },
2111 3156
    "node_modules/concordance": {
2112 3157
      "version": "5.0.4",
2113 3158
      "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz",
2114 3159
      "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==",
2115 3160
      "dev": true,
2165 3210
      "license": "MIT",
2166 3211
      "engines": {
2167 3212
        "node": ">= 0.6"
2168 3213
      }
2169 3214
    },
3215 +
    "node_modules/convert-source-map": {
3216 +
      "version": "1.9.0",
3217 +
      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
3218 +
      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
3219 +
      "dev": true,
3220 +
      "license": "MIT"
3221 +
    },
2170 3222
    "node_modules/convert-to-spaces": {
2171 3223
      "version": "2.0.1",
2172 3224
      "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz",
2173 3225
      "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==",
2174 3226
      "dev": true,
2200 3252
      "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
2201 3253
      "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==",
2202 3254
      "dev": true,
2203 3255
      "license": "MIT"
2204 3256
    },
3257 +
    "node_modules/core-js": {
3258 +
      "version": "2.6.12",
3259 +
      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
3260 +
      "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
3261 +
      "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
3262 +
      "dev": true,
3263 +
      "hasInstallScript": true,
3264 +
      "license": "MIT"
3265 +
    },
2205 3266
    "node_modules/cors": {
2206 3267
      "version": "2.8.6",
2207 3268
      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
2208 3269
      "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
2209 3270
      "license": "MIT",
2239 3300
      },
2240 3301
      "engines": {
2241 3302
        "node": ">= 8"
2242 3303
      }
2243 3304
    },
3305 +
    "node_modules/cross-var": {
3306 +
      "version": "1.1.0",
3307 +
      "resolved": "https://registry.npmjs.org/cross-var/-/cross-var-1.1.0.tgz",
3308 +
      "integrity": "sha512-wIcFax9RNm5ayuORUeJ5MLxPbfh8XdZhhUpKutIszU46Fs9UIhEdPJ7+YguM+7FxEj+68hSQVyathVsIu84SiA==",
3309 +
      "dev": true,
3310 +
      "license": "MIT",
3311 +
      "dependencies": {
3312 +
        "babel-preset-es2015": "^6.18.0",
3313 +
        "babel-preset-stage-0": "^6.16.0",
3314 +
        "babel-register": "^6.18.0",
3315 +
        "cross-spawn": "^5.0.1",
3316 +
        "exit": "^0.1.2"
3317 +
      },
3318 +
      "bin": {
3319 +
        "cross-var": "index.js"
3320 +
      }
3321 +
    },
3322 +
    "node_modules/cross-var/node_modules/cross-spawn": {
3323 +
      "version": "5.1.0",
3324 +
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
3325 +
      "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
3326 +
      "dev": true,
3327 +
      "license": "MIT",
3328 +
      "dependencies": {
3329 +
        "lru-cache": "^4.0.1",
3330 +
        "shebang-command": "^1.2.0",
3331 +
        "which": "^1.2.9"
3332 +
      }
3333 +
    },
3334 +
    "node_modules/cross-var/node_modules/lru-cache": {
3335 +
      "version": "4.1.5",
3336 +
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
3337 +
      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
3338 +
      "dev": true,
3339 +
      "license": "ISC",
3340 +
      "dependencies": {
3341 +
        "pseudomap": "^1.0.2",
3342 +
        "yallist": "^2.1.2"
3343 +
      }
3344 +
    },
3345 +
    "node_modules/cross-var/node_modules/shebang-command": {
3346 +
      "version": "1.2.0",
3347 +
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
3348 +
      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
3349 +
      "dev": true,
3350 +
      "license": "MIT",
3351 +
      "dependencies": {
3352 +
        "shebang-regex": "^1.0.0"
3353 +
      },
3354 +
      "engines": {
3355 +
        "node": ">=0.10.0"
3356 +
      }
3357 +
    },
3358 +
    "node_modules/cross-var/node_modules/shebang-regex": {
3359 +
      "version": "1.0.0",
3360 +
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
3361 +
      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
3362 +
      "dev": true,
3363 +
      "license": "MIT",
3364 +
      "engines": {
3365 +
        "node": ">=0.10.0"
3366 +
      }
3367 +
    },
3368 +
    "node_modules/cross-var/node_modules/which": {
3369 +
      "version": "1.3.1",
3370 +
      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
3371 +
      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
3372 +
      "dev": true,
3373 +
      "license": "ISC",
3374 +
      "dependencies": {
3375 +
        "isexe": "^2.0.0"
3376 +
      },
3377 +
      "bin": {
3378 +
        "which": "bin/which"
3379 +
      }
3380 +
    },
3381 +
    "node_modules/cross-var/node_modules/yallist": {
3382 +
      "version": "2.1.2",
3383 +
      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
3384 +
      "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
3385 +
      "dev": true,
3386 +
      "license": "ISC"
3387 +
    },
2244 3388
    "node_modules/csstype": {
2245 3389
      "version": "3.2.3",
2246 3390
      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
2247 3391
      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
2248 3392
      "devOptional": true,
2377 3521
      "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
2378 3522
      "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
2379 3523
      "devOptional": true,
2380 3524
      "license": "MIT"
2381 3525
    },
3526 +
    "node_modules/detect-indent": {
3527 +
      "version": "4.0.0",
3528 +
      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
3529 +
      "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==",
3530 +
      "dev": true,
3531 +
      "license": "MIT",
3532 +
      "dependencies": {
3533 +
        "repeating": "^2.0.0"
3534 +
      },
3535 +
      "engines": {
3536 +
        "node": ">=0.10.0"
3537 +
      }
3538 +
    },
2382 3539
    "node_modules/detect-libc": {
2383 3540
      "version": "2.1.2",
2384 3541
      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
2385 3542
      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
2386 3543
      "license": "Apache-2.0",
2443 3600
      },
2444 3601
      "funding": {
2445 3602
        "url": "https://dotenvx.com"
2446 3603
      }
2447 3604
    },
3605 +
    "node_modules/dotenv-cli": {
3606 +
      "version": "11.0.0",
3607 +
      "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-11.0.0.tgz",
3608 +
      "integrity": "sha512-r5pA8idbk7GFWuHEU7trSTflWcdBpQEK+Aw17UrSHjS6CReuhrrPcyC3zcQBPQvhArRHnBo/h6eLH1fkCvNlww==",
3609 +
      "dev": true,
3610 +
      "license": "MIT",
3611 +
      "dependencies": {
3612 +
        "cross-spawn": "^7.0.6",
3613 +
        "dotenv": "^17.1.0",
3614 +
        "dotenv-expand": "^12.0.0",
3615 +
        "minimist": "^1.2.6"
3616 +
      },
3617 +
      "bin": {
3618 +
        "dotenv": "cli.js"
3619 +
      }
3620 +
    },
3621 +
    "node_modules/dotenv-cli/node_modules/dotenv": {
3622 +
      "version": "17.4.1",
3623 +
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz",
3624 +
      "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==",
3625 +
      "dev": true,
3626 +
      "license": "BSD-2-Clause",
3627 +
      "engines": {
3628 +
        "node": ">=12"
3629 +
      },
3630 +
      "funding": {
3631 +
        "url": "https://dotenvx.com"
3632 +
      }
3633 +
    },
3634 +
    "node_modules/dotenv-expand": {
3635 +
      "version": "12.0.3",
3636 +
      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz",
3637 +
      "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==",
3638 +
      "dev": true,
3639 +
      "license": "BSD-2-Clause",
3640 +
      "dependencies": {
3641 +
        "dotenv": "^16.4.5"
3642 +
      },
3643 +
      "engines": {
3644 +
        "node": ">=12"
3645 +
      },
3646 +
      "funding": {
3647 +
        "url": "https://dotenvx.com"
3648 +
      }
3649 +
    },
2448 3650
    "node_modules/dunder-proto": {
2449 3651
      "version": "1.0.1",
2450 3652
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
2451 3653
      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
2452 3654
      "license": "MIT",
2733 3935
      "engines": {
2734 3936
        "node": ">=18"
2735 3937
      },
2736 3938
      "funding": {
2737 3939
        "url": "https://github.com/sponsors/sindresorhus"
3940 +
      }
3941 +
    },
3942 +
    "node_modules/exit": {
3943 +
      "version": "0.1.2",
3944 +
      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
3945 +
      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
3946 +
      "dev": true,
3947 +
      "engines": {
3948 +
        "node": ">= 0.8.0"
2738 3949
      }
2739 3950
    },
2740 3951
    "node_modules/expand-template": {
2741 3952
      "version": "2.0.3",
2742 3953
      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
3215 4426
      },
3216 4427
      "engines": {
3217 4428
        "node": ">= 6"
3218 4429
      }
3219 4430
    },
4431 +
    "node_modules/globals": {
4432 +
      "version": "9.18.0",
4433 +
      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
4434 +
      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
4435 +
      "dev": true,
4436 +
      "license": "MIT",
4437 +
      "engines": {
4438 +
        "node": ">=0.10.0"
4439 +
      }
4440 +
    },
3220 4441
    "node_modules/globby": {
3221 4442
      "version": "14.1.0",
3222 4443
      "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz",
3223 4444
      "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==",
3224 4445
      "dev": true,
3269 4490
      "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz",
3270 4491
      "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==",
3271 4492
      "devOptional": true,
3272 4493
      "license": "MIT"
3273 4494
    },
4495 +
    "node_modules/has-ansi": {
4496 +
      "version": "2.0.0",
4497 +
      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
4498 +
      "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
4499 +
      "dev": true,
4500 +
      "license": "MIT",
4501 +
      "dependencies": {
4502 +
        "ansi-regex": "^2.0.0"
4503 +
      },
4504 +
      "engines": {
4505 +
        "node": ">=0.10.0"
4506 +
      }
4507 +
    },
4508 +
    "node_modules/has-ansi/node_modules/ansi-regex": {
4509 +
      "version": "2.1.1",
4510 +
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
4511 +
      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
4512 +
      "dev": true,
4513 +
      "license": "MIT",
4514 +
      "engines": {
4515 +
        "node": ">=0.10.0"
4516 +
      }
4517 +
    },
3274 4518
    "node_modules/has-symbols": {
3275 4519
      "version": "1.1.0",
3276 4520
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
3277 4521
      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
3278 4522
      "license": "MIT",
3307 4551
      "dependencies": {
3308 4552
        "function-bind": "^1.1.2"
3309 4553
      },
3310 4554
      "engines": {
3311 4555
        "node": ">= 0.4"
4556 +
      }
4557 +
    },
4558 +
    "node_modules/home-or-tmp": {
4559 +
      "version": "2.0.0",
4560 +
      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
4561 +
      "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==",
4562 +
      "dev": true,
4563 +
      "license": "MIT",
4564 +
      "dependencies": {
4565 +
        "os-homedir": "^1.0.0",
4566 +
        "os-tmpdir": "^1.0.1"
4567 +
      },
4568 +
      "engines": {
4569 +
        "node": ">=0.10.0"
3312 4570
      }
3313 4571
    },
3314 4572
    "node_modules/hono": {
3315 4573
      "version": "4.11.4",
3316 4574
      "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz",
3461 4719
      "version": "1.3.8",
3462 4720
      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
3463 4721
      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
3464 4722
      "license": "ISC"
3465 4723
    },
4724 +
    "node_modules/invariant": {
4725 +
      "version": "2.2.4",
4726 +
      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
4727 +
      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
4728 +
      "dev": true,
4729 +
      "license": "MIT",
4730 +
      "dependencies": {
4731 +
        "loose-envify": "^1.0.0"
4732 +
      }
4733 +
    },
3466 4734
    "node_modules/ipaddr.js": {
3467 4735
      "version": "1.9.1",
3468 4736
      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
3469 4737
      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
3470 4738
      "license": "MIT",
3501 4769
      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
3502 4770
      "dev": true,
3503 4771
      "license": "MIT",
3504 4772
      "engines": {
3505 4773
        "node": ">=0.10.0"
4774 +
      }
4775 +
    },
4776 +
    "node_modules/is-finite": {
4777 +
      "version": "1.1.0",
4778 +
      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
4779 +
      "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
4780 +
      "dev": true,
4781 +
      "license": "MIT",
4782 +
      "engines": {
4783 +
        "node": ">=0.10.0"
4784 +
      },
4785 +
      "funding": {
4786 +
        "url": "https://github.com/sponsors/sindresorhus"
3506 4787
      }
3507 4788
    },
3508 4789
    "node_modules/is-fullwidth-code-point": {
3509 4790
      "version": "4.0.0",
3510 4791
      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
3644 4925
      "license": "MIT",
3645 4926
      "engines": {
3646 4927
        "node": ">= 0.8"
3647 4928
      }
3648 4929
    },
4930 +
    "node_modules/js-tokens": {
4931 +
      "version": "3.0.2",
4932 +
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
4933 +
      "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==",
4934 +
      "dev": true,
4935 +
      "license": "MIT"
4936 +
    },
3649 4937
    "node_modules/js-yaml": {
3650 4938
      "version": "3.14.2",
3651 4939
      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
3652 4940
      "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
3653 4941
      "dev": true,
3658 4946
      },
3659 4947
      "bin": {
3660 4948
        "js-yaml": "bin/js-yaml.js"
3661 4949
      }
3662 4950
    },
4951 +
    "node_modules/jsesc": {
4952 +
      "version": "1.3.0",
4953 +
      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
4954 +
      "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==",
4955 +
      "dev": true,
4956 +
      "license": "MIT",
4957 +
      "bin": {
4958 +
        "jsesc": "bin/jsesc"
4959 +
      }
4960 +
    },
3663 4961
    "node_modules/json5": {
3664 4962
      "version": "2.2.3",
3665 4963
      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3666 4964
      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3667 4965
      "dev": true,
3792 5090
      "version": "5.3.2",
3793 5091
      "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
3794 5092
      "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
3795 5093
      "devOptional": true,
3796 5094
      "license": "Apache-2.0"
5095 +
    },
5096 +
    "node_modules/loose-envify": {
5097 +
      "version": "1.4.0",
5098 +
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
5099 +
      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
5100 +
      "dev": true,
5101 +
      "license": "MIT",
5102 +
      "dependencies": {
5103 +
        "js-tokens": "^3.0.0 || ^4.0.0"
5104 +
      },
5105 +
      "bin": {
5106 +
        "loose-envify": "cli.js"
5107 +
      }
3797 5108
    },
3798 5109
    "node_modules/lru-cache": {
3799 5110
      "version": "10.4.3",
3800 5111
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
3801 5112
      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
4056 5367
      },
4057 5368
      "engines": {
4058 5369
        "node": ">= 18"
4059 5370
      }
4060 5371
    },
5372 +
    "node_modules/mkdirp": {
5373 +
      "version": "0.5.6",
5374 +
      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
5375 +
      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
5376 +
      "dev": true,
5377 +
      "license": "MIT",
5378 +
      "dependencies": {
5379 +
        "minimist": "^1.2.6"
5380 +
      },
5381 +
      "bin": {
5382 +
        "mkdirp": "bin/cmd.js"
5383 +
      }
5384 +
    },
4061 5385
    "node_modules/mkdirp-classic": {
4062 5386
      "version": "0.5.3",
4063 5387
      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
4064 5388
      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
4065 5389
      "license": "MIT"
4375 5699
      "license": "ISC",
4376 5700
      "dependencies": {
4377 5701
        "wrappy": "1"
4378 5702
      }
4379 5703
    },
5704 +
    "node_modules/os-homedir": {
5705 +
      "version": "1.0.2",
5706 +
      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
5707 +
      "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==",
5708 +
      "dev": true,
5709 +
      "license": "MIT",
5710 +
      "engines": {
5711 +
        "node": ">=0.10.0"
5712 +
      }
5713 +
    },
5714 +
    "node_modules/os-tmpdir": {
5715 +
      "version": "1.0.2",
5716 +
      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
5717 +
      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
5718 +
      "dev": true,
5719 +
      "license": "MIT",
5720 +
      "engines": {
5721 +
        "node": ">=0.10.0"
5722 +
      }
5723 +
    },
4380 5724
    "node_modules/p-map": {
4381 5725
      "version": "7.0.4",
4382 5726
      "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
4383 5727
      "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==",
4384 5728
      "dev": true,
4432 5776
      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
4433 5777
      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
4434 5778
      "license": "MIT",
4435 5779
      "engines": {
4436 5780
        "node": ">= 0.8"
5781 +
      }
5782 +
    },
5783 +
    "node_modules/path-is-absolute": {
5784 +
      "version": "1.0.1",
5785 +
      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
5786 +
      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
5787 +
      "dev": true,
5788 +
      "license": "MIT",
5789 +
      "engines": {
5790 +
        "node": ">=0.10.0"
4437 5791
      }
4438 5792
    },
4439 5793
    "node_modules/path-key": {
4440 5794
      "version": "3.1.1",
4441 5795
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
4779 6133
        "typescript": {
4780 6134
          "optional": true
4781 6135
        }
4782 6136
      }
4783 6137
    },
6138 +
    "node_modules/private": {
6139 +
      "version": "0.1.8",
6140 +
      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
6141 +
      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
6142 +
      "dev": true,
6143 +
      "license": "MIT",
6144 +
      "engines": {
6145 +
        "node": ">= 0.6"
6146 +
      }
6147 +
    },
4784 6148
    "node_modules/proper-lockfile": {
4785 6149
      "version": "4.1.2",
4786 6150
      "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
4787 6151
      "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
4788 6152
      "devOptional": true,
4810 6174
        "ipaddr.js": "1.9.1"
4811 6175
      },
4812 6176
      "engines": {
4813 6177
        "node": ">= 0.10"
4814 6178
      }
6179 +
    },
6180 +
    "node_modules/pseudomap": {
6181 +
      "version": "1.0.2",
6182 +
      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
6183 +
      "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
6184 +
      "dev": true,
6185 +
      "license": "ISC"
4815 6186
    },
4816 6187
    "node_modules/pump": {
4817 6188
      "version": "3.0.3",
4818 6189
      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
4819 6190
      "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
4987 6358
      "funding": {
4988 6359
        "type": "individual",
4989 6360
        "url": "https://paulmillr.com/funding/"
4990 6361
      }
4991 6362
    },
6363 +
    "node_modules/regenerate": {
6364 +
      "version": "1.4.2",
6365 +
      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
6366 +
      "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
6367 +
      "dev": true,
6368 +
      "license": "MIT"
6369 +
    },
6370 +
    "node_modules/regenerator-runtime": {
6371 +
      "version": "0.11.1",
6372 +
      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
6373 +
      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
6374 +
      "dev": true,
6375 +
      "license": "MIT"
6376 +
    },
6377 +
    "node_modules/regenerator-transform": {
6378 +
      "version": "0.10.1",
6379 +
      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
6380 +
      "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
6381 +
      "dev": true,
6382 +
      "license": "BSD",
6383 +
      "dependencies": {
6384 +
        "babel-runtime": "^6.18.0",
6385 +
        "babel-types": "^6.19.0",
6386 +
        "private": "^0.1.6"
6387 +
      }
6388 +
    },
4992 6389
    "node_modules/regexp-to-ast": {
4993 6390
      "version": "0.5.0",
4994 6391
      "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz",
4995 6392
      "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==",
4996 6393
      "devOptional": true,
4997 6394
      "license": "MIT"
4998 6395
    },
6396 +
    "node_modules/regexpu-core": {
6397 +
      "version": "2.0.0",
6398 +
      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
6399 +
      "integrity": "sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ==",
6400 +
      "dev": true,
6401 +
      "license": "MIT",
6402 +
      "dependencies": {
6403 +
        "regenerate": "^1.2.1",
6404 +
        "regjsgen": "^0.2.0",
6405 +
        "regjsparser": "^0.1.4"
6406 +
      }
6407 +
    },
6408 +
    "node_modules/regjsgen": {
6409 +
      "version": "0.2.0",
6410 +
      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
6411 +
      "integrity": "sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==",
6412 +
      "dev": true,
6413 +
      "license": "MIT"
6414 +
    },
6415 +
    "node_modules/regjsparser": {
6416 +
      "version": "0.1.5",
6417 +
      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
6418 +
      "integrity": "sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw==",
6419 +
      "dev": true,
6420 +
      "license": "BSD",
6421 +
      "dependencies": {
6422 +
        "jsesc": "~0.5.0"
6423 +
      },
6424 +
      "bin": {
6425 +
        "regjsparser": "bin/parser"
6426 +
      }
6427 +
    },
6428 +
    "node_modules/regjsparser/node_modules/jsesc": {
6429 +
      "version": "0.5.0",
6430 +
      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
6431 +
      "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
6432 +
      "dev": true,
6433 +
      "bin": {
6434 +
        "jsesc": "bin/jsesc"
6435 +
      }
6436 +
    },
4999 6437
    "node_modules/remeda": {
5000 6438
      "version": "2.33.4",
5001 6439
      "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz",
5002 6440
      "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==",
5003 6441
      "devOptional": true,
5004 6442
      "license": "MIT",
5005 6443
      "funding": {
5006 6444
        "url": "https://github.com/sponsors/remeda"
6445 +
      }
6446 +
    },
6447 +
    "node_modules/repeating": {
6448 +
      "version": "2.0.1",
6449 +
      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
6450 +
      "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==",
6451 +
      "dev": true,
6452 +
      "license": "MIT",
6453 +
      "dependencies": {
6454 +
        "is-finite": "^1.0.0"
6455 +
      },
6456 +
      "engines": {
6457 +
        "node": ">=0.10.0"
5007 6458
      }
5008 6459
    },
5009 6460
    "node_modules/require-directory": {
5010 6461
      "version": "2.1.1",
5011 6462
      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
5402 6853
      },
5403 6854
      "funding": {
5404 6855
        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
5405 6856
      }
5406 6857
    },
6858 +
    "node_modules/source-map": {
6859 +
      "version": "0.5.7",
6860 +
      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
6861 +
      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
6862 +
      "dev": true,
6863 +
      "license": "BSD-3-Clause",
6864 +
      "engines": {
6865 +
        "node": ">=0.10.0"
6866 +
      }
6867 +
    },
6868 +
    "node_modules/source-map-support": {
6869 +
      "version": "0.4.18",
6870 +
      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
6871 +
      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
6872 +
      "dev": true,
6873 +
      "license": "MIT",
6874 +
      "dependencies": {
6875 +
        "source-map": "^0.5.6"
6876 +
      }
6877 +
    },
5407 6878
    "node_modules/split2": {
5408 6879
      "version": "4.2.0",
5409 6880
      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
5410 6881
      "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
5411 6882
      "license": "ISC",
5673 7144
      },
5674 7145
      "engines": {
5675 7146
        "node": ">=14.18.0"
5676 7147
      }
5677 7148
    },
7149 +
    "node_modules/supports-color": {
7150 +
      "version": "2.0.0",
7151 +
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
7152 +
      "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
7153 +
      "dev": true,
7154 +
      "license": "MIT",
7155 +
      "engines": {
7156 +
        "node": ">=0.8.0"
7157 +
      }
7158 +
    },
5678 7159
    "node_modules/tar": {
5679 7160
      "version": "7.5.2",
5680 7161
      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz",
5681 7162
      "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==",
5682 7163
      "dev": true,
5758 7239
      "license": "MIT",
5759 7240
      "engines": {
5760 7241
        "node": ">=18"
5761 7242
      }
5762 7243
    },
7244 +
    "node_modules/to-fast-properties": {
7245 +
      "version": "1.0.3",
7246 +
      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
7247 +
      "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==",
7248 +
      "dev": true,
7249 +
      "license": "MIT",
7250 +
      "engines": {
7251 +
        "node": ">=0.10.0"
7252 +
      }
7253 +
    },
5763 7254
    "node_modules/to-regex-range": {
5764 7255
      "version": "5.0.1",
5765 7256
      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
5766 7257
      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
5767 7258
      "dev": true,
5786 7277
      "version": "0.0.3",
5787 7278
      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
5788 7279
      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
5789 7280
      "dev": true,
5790 7281
      "license": "MIT"
7282 +
    },
7283 +
    "node_modules/trim-right": {
7284 +
      "version": "1.0.1",
7285 +
      "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
7286 +
      "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==",
7287 +
      "dev": true,
7288 +
      "license": "MIT",
7289 +
      "engines": {
7290 +
        "node": ">=0.10.0"
7291 +
      }
5791 7292
    },
5792 7293
    "node_modules/ts-node": {
5793 7294
      "version": "10.9.2",
5794 7295
      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
5795 7296
      "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
6444 7945
        "graphmatch": "^1.1.0"
6445 7946
      }
6446 7947
    }
6447 7948
  }
6448 7949
}
api/package.json modified+5 -3
api/package.json
1 1
{
2 2
  "name": "orbit-api",
3 3
  "version": "0.0.0",
4 4
  "description": "",
5 5
  "license": "ISC",
9 9
    "test": "tests"
10 10
  },
11 11
  "scripts": {
12 12
    "build": "tsc && tsc-alias",
13 13
    "start": "ts-node -r tsconfig-paths/register src/index.ts",
14 -
    "test": "npm run test:setup && NODE_ENV=test npx ava tests/database.test.ts",
14 +
    "test": "npm run test:setup && NODE_ENV=test npx ava",
15 15
    "test:setup": "npm run test:setup:generate && npm run test:setup:migrate",
16 -
    "test:setup:generate": "DATABASE_URL='postgres://user:password@orbit_db:5432/orbit_test' npx prisma generate",
17 -
    "test:setup:migrate": "DATABASE_URL='postgres://user:password@orbit_db:5432/orbit_test' npx prisma migrate deploy",
16 +
    "test:setup:generate": "dotenv -e .env.test npx prisma generate",
17 +
    "test:setup:migrate": "dotenv -e .env.test npx prisma db push",
18 18
    "test:watch": "npm run test:setup && NODE_ENV=test npx ava --watch",
19 19
    "dev": "prisma generate && prisma migrate deploy && npm run start"
20 20
  },
21 21
  "dependencies": {
22 22
    "@prisma/adapter-better-sqlite3": "^7.5.0",
38 38
    "@types/better-sqlite3": "^7.6.13",
39 39
    "@types/express": "^5.0.6",
40 40
    "@types/morgan": "^1.9.10",
41 41
    "@types/node": "^25.5.2",
42 42
    "ava": "^6.4.1",
43 +
    "cross-var": "^1.1.0",
44 +
    "dotenv-cli": "^11.0.0",
43 45
    "prisma": "^7.5.0",
44 46
    "supertest": "^7.1.4",
45 47
    "ts-node": "^10.9.2",
46 48
    "tsc-alias": "^1.8.16",
47 49
    "tsconfig-paths": "^4.2.0",
48 50
    "tsx": "^4.21.0",
49 51
    "typescript": "^6.0.2"
50 52
  }
51 53
}
/dev/null → api/tests/database-auth.test.ts
1 +
import test from "ava";
2 +
import { PrismaClient } from '@prisma/client';
3 +
import { PrismaPg } from '@prisma/adapter-pg';
4 +
import bcrypt from 'bcryptjs';
5 +
import 'dotenv/config';
6 +

7 +
let prisma: PrismaClient;
8 +

9 +
test.before(() => {
10 +
  process.env.NODE_ENV = 'test';
11 +

12 +
  const connectionString = process.env.DATABASE_URL || 'postgres://user:password@orbit_db:5432/orbit_test';
13 +
  const adapter = new PrismaPg({ connectionString });
14 +
  prisma = new PrismaClient({ adapter });
15 +
});
16 +

17 +
test.beforeEach(async () => {
18 +
  // Clean database before each test
19 +
  try {
20 +
    await prisma.user.deleteMany({});
21 +
  } catch (err) {
22 +
    console.error('Error cleaning test DB:', err);
23 +
  }
24 +
});
25 +

26 +
test.after.always(async () => {
27 +
  await prisma?.$disconnect();
28 +
});
29 +

30 +
// Basic database connectivity test
31 +
test("database connection works", async (t) => {
32 +
  const result = await prisma.$queryRaw`SELECT 1 as test`;
33 +
  t.truthy(result);
34 +
});
35 +

36 +
// User creation and authentication tests
37 +
test("can create user with encrypted password", async (t) => {
38 +
  const encryptedPassword = bcrypt.hashSync("testPassword123", 10);
39 +

40 +
  const user = await prisma.user.create({
41 +
    data: {
42 +
      email: "test@example.com",
43 +
      firstName: "Test",
44 +
      lastName: "User",
45 +
      encryptedPassword: encryptedPassword
46 +
    }
47 +
  });
48 +

49 +
  t.is(user.email, "test@example.com");
50 +
  t.is(user.firstName, "Test");
51 +
  t.truthy(user.id);
52 +

53 +
  // Verify password can be validated
54 +
  t.true(bcrypt.compareSync("testPassword123", user.encryptedPassword));
55 +
  t.false(bcrypt.compareSync("wrongPassword", user.encryptedPassword));
56 +
});
57 +

58 +
test("can find user by email for authentication", async (t) => {
59 +
  // Create user
60 +
  await prisma.user.create({
61 +
    data: {
62 +
      email: "login@example.com",
63 +
      firstName: "Login",
64 +
      lastName: "User",
65 +
      encryptedPassword: bcrypt.hashSync("password123", 10)
66 +
    }
67 +
  });
68 +

69 +
  // Simulate login lookup
70 +
  const foundUser = await prisma.user.findUnique({
71 +
    where: { email: "login@example.com" }
72 +
  });
73 +

74 +
  t.truthy(foundUser);
75 +
  t.is(foundUser!.email, "login@example.com");
76 +
  t.true(bcrypt.compareSync("password123", foundUser!.encryptedPassword));
77 +
  t.false(bcrypt.compareSync("wrongPassword", foundUser!.encryptedPassword));
78 +
});
79 +

80 +
test("email uniqueness constraint prevents duplicate registrations", async (t) => {
81 +
  const email = "duplicate@example.com";
82 +

83 +
  // Create first user
84 +
  await prisma.user.create({
85 +
    data: {
86 +
      email,
87 +
      firstName: "First",
88 +
      lastName: "User",
89 +
      encryptedPassword: bcrypt.hashSync("password", 10)
90 +
    }
91 +
  });
92 +

93 +
  // Try to create second user with same email - should fail
94 +
  await t.throwsAsync(
95 +
    async () => {
96 +
      await prisma.user.create({
97 +
        data: {
98 +
          email,
99 +
          firstName: "Second",
100 +
          lastName: "User",
101 +
          encryptedPassword: bcrypt.hashSync("password", 10)
102 +
        }
103 +
      });
104 +
    }
105 +
  );
106 +
});
107 +

108 +
test("password reset flow works with database", async (t) => {
109 +
  const resetToken = "reset-token-123";
110 +
  const resetExpires = new Date(Date.now() + 3600000); // 1 hour from now
111 +

112 +
  // Create user
113 +
  const user = await prisma.user.create({
114 +
    data: {
115 +
      email: "reset@example.com",
116 +
      firstName: "Reset",
117 +
      lastName: "User",
118 +
      encryptedPassword: bcrypt.hashSync("oldPassword", 10)
119 +
    }
120 +
  });
121 +

122 +
  // Step 1: Set reset token (forgot password)
123 +
  await prisma.user.update({
124 +
    where: { id: user.id },
125 +
    data: {
126 +
      passwordResetToken: resetToken,
127 +
      passwordResetExpires: resetExpires
128 +
    }
129 +
  });
130 +

131 +
  // Step 2: Find user by reset token
132 +
  const userWithToken = await prisma.user.findFirst({
133 +
    where: {
134 +
      passwordResetToken: resetToken,
135 +
      passwordResetExpires: { gte: new Date() } // Token not expired
136 +
    }
137 +
  });
138 +

139 +
  t.truthy(userWithToken);
140 +
  t.is(userWithToken!.email, "reset@example.com");
141 +

142 +
  // Step 3: Reset password
143 +
  const newPassword = bcrypt.hashSync("newPassword123", 10);
144 +
  const updatedUser = await prisma.user.update({
145 +
    where: { id: user.id },
146 +
    data: {
147 +
      encryptedPassword: newPassword,
148 +
      passwordResetToken: null,
149 +
      passwordResetExpires: null
150 +
    }
151 +
  });
152 +

153 +
  // Verify new password works and reset fields are cleared
154 +
  t.true(bcrypt.compareSync("newPassword123", updatedUser.encryptedPassword));
155 +
  t.false(bcrypt.compareSync("oldPassword", updatedUser.encryptedPassword));
156 +
  t.is(updatedUser.passwordResetToken, null);
157 +
  t.is(updatedUser.passwordResetExpires, null);
158 +
});
159 +

160 +
test("expired reset tokens are not found", async (t) => {
161 +
  const expiredResetToken = "expired-token";
162 +
  const pastDate = new Date(Date.now() - 3600000); // 1 hour ago
163 +

164 +
  // Create user with expired token
165 +
  const user = await prisma.user.create({
166 +
    data: {
167 +
      email: "expired@example.com",
168 +
      firstName: "Expired",
169 +
      lastName: "User",
170 +
      encryptedPassword: bcrypt.hashSync("password", 10),
171 +
      passwordResetToken: expiredResetToken,
172 +
      passwordResetExpires: pastDate
173 +
    }
174 +
  });
175 +

176 +
  // Try to find user by expired token
177 +
  const foundUser = await prisma.user.findFirst({
178 +
    where: {
179 +
      passwordResetToken: expiredResetToken,
180 +
      passwordResetExpires: { gte: new Date() } // Token not expired
181 +
    }
182 +
  });
183 +

184 +
  // Should not find the user because token is expired
185 +
  t.is(foundUser, null);
186 +

187 +
  // But user still exists
188 +
  const stillExists = await prisma.user.findUnique({ where: { id: user.id } });
189 +
  t.truthy(stillExists);
190 +
});
191 +

192 +
test("user profile update works", async (t) => {
193 +
  // Create user
194 +
  const user = await prisma.user.create({
195 +
    data: {
196 +
      email: "profile@example.com",
197 +
      firstName: "Original",
198 +
      lastName: "Name",
199 +
      encryptedPassword: bcrypt.hashSync("password", 10)
200 +
    }
201 +
  });
202 +

203 +
  // Update profile
204 +
  const updatedUser = await prisma.user.update({
205 +
    where: { id: user.id },
206 +
    data: {
207 +
      firstName: "Updated",
208 +
      lastName: "Profile"
209 +
    }
210 +
  });
211 +

212 +
  t.is(updatedUser.firstName, "Updated");
213 +
  t.is(updatedUser.lastName, "Profile");
214 +
  t.is(updatedUser.email, "profile@example.com"); // Should remain unchanged
215 +
  t.true(updatedUser.updatedAt > user.updatedAt); // updatedAt should be newer
216 +
});
217 +

218 +
test("timestamps are automatically managed", async (t) => {
219 +
  const beforeCreate = new Date();
220 +

221 +
  const user = await prisma.user.create({
222 +
    data: {
223 +
      email: "timestamps@example.com",
224 +
      firstName: "Time",
225 +
      lastName: "Stamps",
226 +
      encryptedPassword: bcrypt.hashSync("password", 10)
227 +
    }
228 +
  });
229 +

230 +
  const afterCreate = new Date();
231 +

232 +
  // Check creation timestamps
233 +
  t.true(user.createdAt >= beforeCreate);
234 +
  t.true(user.createdAt <= afterCreate);
235 +
  t.true(user.updatedAt >= beforeCreate);
236 +
  t.true(user.updatedAt <= afterCreate);
237 +

238 +
  // Wait and update to test updatedAt behavior
239 +
  await new Promise(resolve => setTimeout(resolve, 100));
240 +
  const beforeUpdate = new Date();
241 +

242 +
  const updatedUser = await prisma.user.update({
243 +
    where: { id: user.id },
244 +
    data: { firstName: "Updated" }
245 +
  });
246 +

247 +
  const afterUpdate = new Date();
248 +

249 +
  // createdAt should remain the same, updatedAt should be newer
250 +
  t.deepEqual(updatedUser.createdAt, user.createdAt);
251 +
  t.true(updatedUser.updatedAt >= beforeUpdate);
252 +
  t.true(updatedUser.updatedAt <= afterUpdate);
253 +
  t.true(updatedUser.updatedAt > user.updatedAt);
254 +
});
api/tests/mood.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "./test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -
let userId;
9 -

10 -
test.before(() => {
11 -
  db = setupTestDb();
12 -
  app = createApp(db);
13 -
});
14 -

15 -
test.beforeEach(async () => {
16 -
  cleanupTestDb();
17 -

18 -
  // Create a user for the mood tests
19 -
  const res = await request(app)
20 -
    .post("/users")
21 -
    .send({
22 -
      email: "maria@example.com",
23 -
      password: "123456",
24 -
      first_name: "Maria",
25 -
      last_name: "Silva",
26 -
    });
27 -

28 -
  userId = res.body.id;
29 -
});
30 -

31 -
test.serial("Registrar humor", async (t) => {
32 -
  const res = await request(app).post("/mood").send({
33 -
    user_id: userId,
34 -
    stress_level: 3,
35 -
    anxiety_level: 4,
36 -
    energy_level: 5,
37 -
    title: "Bad day",
38 -
    description: "Stressado com a faculdade",
39 -
    recorded_at: new Date().toISOString()
40 -
  });
41 -

42 -
  t.is(res.status, 201);
43 -
  t.truthy(res.body.id);
44 -
});
45 -

46 -
test.serial("Listar humores do usuário", async (t) => {
47 -
  const res = await request(app).get(`/mood/user/${userId}`);
48 -
  t.is(res.status, 200);
49 -
  t.true(Array.isArray(res.body.moods));
50 -
});
51 -

52 -
test.serial("Falha ao registrar humor sem stress_level", async (t) => {
53 -
  const res = await request(app).post("/mood").send({
54 -
    user_id: userId,
55 -
    anxiety_level: 4,
56 -
    energy_level: 5,
57 -
    title: "Test",
58 -
    recorded_at: new Date().toISOString()
59 -
  });
60 -

61 -
  t.is(res.status, 400);
62 -
  t.is(res.body.error, "Campos faltantes");
63 -
});
64 -

65 -
test.serial("Listar múltiplos humores do usuário", async (t) => {
66 -
  // Ensure we have a valid userId
67 -
  t.truthy(userId, "userId should be defined");
68 -

69 -
  // Create first mood entry
70 -
  const res1 = await request(app).post("/mood").send({
71 -
    user_id: userId,
72 -
    stress_level: 3,
73 -
    anxiety_level: 4,
74 -
    energy_level: 6,
75 -
    title: "Morning",
76 -
    description: "Morning mood",
77 -
    recorded_at: new Date().toISOString()
78 -
  });
79 -
  t.is(res1.status, 201);
80 -

81 -
  // Create second mood entry
82 -
  const res2 = await request(app).post("/mood").send({
83 -
    user_id: userId,
84 -
    stress_level: 2,
85 -
    anxiety_level: 2,
86 -
    energy_level: 8,
87 -
    title: "Evening",
88 -
    description: "Evening mood",
89 -
    recorded_at: new Date().toISOString()
90 -
  });
91 -
  t.is(res2.status, 201);
92 -

93 -
  const res = await request(app).get(`/mood/user/${userId}`);
94 -
  t.is(res.status, 200);
95 -
  t.true(Array.isArray(res.body.moods));
96 -
  t.is(res.body.moods.length, 2);
97 -
});
98 -

api/tests/mood/creation.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -
let userId;
9 -

10 -
test.before(() => {
11 -
  db = setupTestDb();
12 -
  app = createApp(db);
13 -
});
14 -

15 -
test.beforeEach(async () => {
16 -
  cleanupTestDb();
17 -

18 -
  // Create a test user with unique email
19 -
  const uniqueEmail = `mood_${Date.now()}_${Math.random()}@example.com`;
20 -
  const res = await request(app)
21 -
    .post("/users")
22 -
    .send({
23 -
      email: uniqueEmail,
24 -
      password: "senha123",
25 -
      first_name: "Mood",
26 -
      last_name: "Tester"
27 -
    });
28 -

29 -
  if (res.status !== 201) {
30 -
    throw new Error(`Failed to create test user: ${JSON.stringify(res.body)}`);
31 -
  }
32 -

33 -
  userId = res.body.id;
34 -
});
35 -

36 -
test("Criar registro de humor com todos os campos obrigatórios", async (t) => {
37 -
  const now = new Date().toISOString();
38 -

39 -
  const res = await request(app)
40 -
    .post("/mood")
41 -
    .send({
42 -
      user_id: userId,
43 -
      stress_level: 3,
44 -
      anxiety_level: 4,
45 -
      energy_level: 7,
46 -
      recorded_at: now
47 -
    });
48 -

49 -
  t.is(res.status, 201);
50 -
  t.truthy(res.body.id);
51 -
});
52 -

53 -
test("Criar registro de humor com avaliação e descrição", async (t) => {
54 -
  const now = new Date().toISOString();
55 -

56 -
  const res = await request(app)
57 -
    .post("/mood")
58 -
    .send({
59 -
      user_id: userId,
60 -
      rating: 8,
61 -
      stress_level: 2,
62 -
      anxiety_level: 3,
63 -
      energy_level: 9,
64 -
      title: "Dia produtivo",
65 -
      description: "Consegui terminar todas as tarefas",
66 -
      recorded_at: now
67 -
    });
68 -

69 -
  t.is(res.status, 201);
70 -

71 -
  // Verify data was saved correctly
72 -
  const mood = db.prepare("SELECT * FROM mood WHERE id = ?").get(res.body.id);
73 -
  t.is(mood.rating, 8);
74 -
  t.is(mood.stress_level, 2);
75 -
  t.is(mood.title, "Dia produtivo");
76 -
});
77 -

78 -
test("Criar registro de humor com componentes emocionais", async (t) => {
79 -
  const now = new Date().toISOString();
80 -

81 -
  const res = await request(app)
82 -
    .post("/mood")
83 -
    .send({
84 -
      user_id: userId,
85 -
      stress_level: 5,
86 -
      anxiety_level: 6,
87 -
      energy_level: 4,
88 -
      recorded_at: now,
89 -
      mood_components: [
90 -
        { emotion: "joy", intensity: 7 },
91 -
        { emotion: "anxiety", intensity: 6 },
92 -
        { emotion: "trust", intensity: 8 }
93 -
      ]
94 -
    });
95 -

96 -
  t.is(res.status, 201);
97 -

98 -
  // Verify components were saved
99 -
  const components = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").all(res.body.id);
100 -
  t.is(components.length, 3);
101 -

102 -
  const emotions = components.map(c => c.emotion);
103 -
  t.true(emotions.includes('joy'));
104 -
  t.true(emotions.includes('anxiety'));
105 -
  t.true(emotions.includes('trust'));
106 -
});
107 -

108 -
test("Componentes emocionais devem aceitar maiúsculas e converter para minúsculas", async (t) => {
109 -
  const now = new Date().toISOString();
110 -

111 -
  const res = await request(app)
112 -
    .post("/mood")
113 -
    .send({
114 -
      user_id: userId,
115 -
      stress_level: 5,
116 -
      anxiety_level: 6,
117 -
      energy_level: 4,
118 -
      recorded_at: now,
119 -
      mood_components: [
120 -
        { emotion: "JOY", intensity: 7 },
121 -
        { emotion: "AnXiEtY", intensity: 6 }
122 -
      ]
123 -
    });
124 -

125 -
  t.is(res.status, 201);
126 -

127 -
  // Verify emotions were lowercased
128 -
  const components = db.prepare("SELECT emotion FROM mood_components WHERE mood_id = ? ORDER BY emotion ASC").all(res.body.id);
129 -
  t.is(components[0].emotion, 'anxiety');
130 -
  t.is(components[1].emotion, 'joy');
131 -
});
132 -

133 -
test("Falha ao criar registro de humor sem ID de usuário", async (t) => {
134 -
  const now = new Date().toISOString();
135 -

136 -
  const res = await request(app)
137 -
    .post("/mood")
138 -
    .send({
139 -
      stress_level: 3,
140 -
      anxiety_level: 4,
141 -
      energy_level: 7,
142 -
      recorded_at: now
143 -
    });
144 -

145 -
  t.is(res.status, 400);
146 -
  t.is(res.body.error, "Campos faltantes");
147 -
  t.true(res.body.missing.includes('user_id'));
148 -
});
149 -

150 -
test("Falha ao criar registro de humor sem nível de stress", async (t) => {
151 -
  const now = new Date().toISOString();
152 -

153 -
  const res = await request(app)
154 -
    .post("/mood")
155 -
    .send({
156 -
      user_id: userId,
157 -
      anxiety_level: 4,
158 -
      energy_level: 7,
159 -
      recorded_at: now
160 -
    });
161 -

162 -
  t.is(res.status, 400);
163 -
  t.is(res.body.error, "Campos faltantes");
164 -
  t.true(res.body.missing.includes('stress_level'));
165 -
});
166 -

167 -
test("Falha ao criar registro de humor sem nível de ansiedade", async (t) => {
168 -
  const now = new Date().toISOString();
169 -

170 -
  const res = await request(app)
171 -
    .post("/mood")
172 -
    .send({
173 -
      user_id: userId,
174 -
      stress_level: 3,
175 -
      energy_level: 7,
176 -
      recorded_at: now
177 -
    });
178 -

179 -
  t.is(res.status, 400);
180 -
  t.is(res.body.error, "Campos faltantes");
181 -
  t.true(res.body.missing.includes('anxiety_level'));
182 -
});
183 -

184 -
test("Falha ao criar registro de humor sem nível de energia", async (t) => {
185 -
  const now = new Date().toISOString();
186 -

187 -
  const res = await request(app)
188 -
    .post("/mood")
189 -
    .send({
190 -
      user_id: userId,
191 -
      stress_level: 3,
192 -
      anxiety_level: 4,
193 -
      recorded_at: now
194 -
    });
195 -

196 -
  t.is(res.status, 400);
197 -
  t.is(res.body.error, "Campos faltantes");
198 -
  t.true(res.body.missing.includes('energy_level'));
199 -
});
200 -

201 -
test("Falha ao criar registro de humor sem data de registro", async (t) => {
202 -
  const res = await request(app)
203 -
    .post("/mood")
204 -
    .send({
205 -
      user_id: userId,
206 -
      stress_level: 3,
207 -
      anxiety_level: 4,
208 -
      energy_level: 7
209 -
    });
210 -

211 -
  t.is(res.status, 400);
212 -
  t.is(res.body.error, "Campos faltantes");
213 -
  t.true(res.body.missing.includes('recorded_at'));
214 -
});
215 -

216 -
test("Falha ao criar registro de humor com nível de estresse inválido (menor que 1)", async (t) => {
217 -
  const now = new Date().toISOString();
218 -

219 -
  const res = await request(app)
220 -
    .post("/mood")
221 -
    .send({
222 -
      user_id: userId,
223 -
      stress_level: 0,
224 -
      anxiety_level: 4,
225 -
      energy_level: 7,
226 -
      recorded_at: now
227 -
    });
228 -

229 -
  t.is(res.status, 400);
230 -
  t.is(res.body.error, "stress_level deve ser entre 1 e 10");
231 -
});
232 -

233 -
test("Falha ao criar registro de humor com nível de estresse inválido (maior que 10)", async (t) => {
234 -
  const now = new Date().toISOString();
235 -

236 -
  const res = await request(app)
237 -
    .post("/mood")
238 -
    .send({
239 -
      user_id: userId,
240 -
      stress_level: 11,
241 -
      anxiety_level: 4,
242 -
      energy_level: 7,
243 -
      recorded_at: now
244 -
    });
245 -

246 -
  t.is(res.status, 400);
247 -
  t.is(res.body.error, "stress_level deve ser entre 1 e 10");
248 -
});
249 -

250 -
test("Falha ao criar registro de humor com nível de ansiedade inválido", async (t) => {
251 -
  const now = new Date().toISOString();
252 -

253 -
  const res = await request(app)
254 -
    .post("/mood")
255 -
    .send({
256 -
      user_id: userId,
257 -
      stress_level: 3,
258 -
      anxiety_level: 15,
259 -
      energy_level: 7,
260 -
      recorded_at: now
261 -
    });
262 -

263 -
  t.is(res.status, 400);
264 -
  t.is(res.body.error, "anxiety_level deve ser entre 1 e 10");
265 -
});
266 -

267 -
test("Falha ao criar registro de humor com nível de energia inválido", async (t) => {
268 -
  const now = new Date().toISOString();
269 -

270 -
  const res = await request(app)
271 -
    .post("/mood")
272 -
    .send({
273 -
      user_id: userId,
274 -
      stress_level: 3,
275 -
      anxiety_level: 4,
276 -
      energy_level: -5,
277 -
      recorded_at: now
278 -
    });
279 -

280 -
  t.is(res.status, 400);
281 -
  t.is(res.body.error, "energy_level deve ser entre 1 e 10");
282 -
});
283 -

284 -
test("Falha ao criar registro de humor com avaliação inválido", async (t) => {
285 -
  const now = new Date().toISOString();
286 -

287 -
  const res = await request(app)
288 -
    .post("/mood")
289 -
    .send({
290 -
      user_id: userId,
291 -
      rating: 20,
292 -
      stress_level: 3,
293 -
      anxiety_level: 4,
294 -
      energy_level: 7,
295 -
      recorded_at: now
296 -
    });
297 -

298 -
  t.is(res.status, 400);
299 -
  t.is(res.body.error, "rating deve ser entre 1 e 10");
300 -
});
301 -

302 -
test("Falha ao criar registro de humor com data inválida", async (t) => {
303 -
  const res = await request(app)
304 -
    .post("/mood")
305 -
    .send({
306 -
      user_id: userId,
307 -
      stress_level: 3,
308 -
      anxiety_level: 4,
309 -
      energy_level: 7,
310 -
      recorded_at: "data-invalida"
311 -
    });
312 -

313 -
  t.is(res.status, 400);
314 -
  t.is(res.body.error, "recorded_at deve ser uma data válida");
315 -
});
316 -

317 -
test("Falha ao criar registro de humor com data no futuro", async (t) => {
318 -
  const futureDate = new Date();
319 -
  futureDate.setDate(futureDate.getDate() + 1);
320 -

321 -
  const res = await request(app)
322 -
    .post("/mood")
323 -
    .send({
324 -
      user_id: userId,
325 -
      stress_level: 3,
326 -
      anxiety_level: 4,
327 -
      energy_level: 7,
328 -
      recorded_at: futureDate.toISOString()
329 -
    });
330 -

331 -
  t.is(res.status, 400);
332 -
  t.is(res.body.error, "recorded_at não pode ser no futuro");
333 -
});
334 -

335 -
test("Falha ao criar registro de humor com emoção inválida", async (t) => {
336 -
  const now = new Date().toISOString();
337 -

338 -
  const res = await request(app)
339 -
    .post("/mood")
340 -
    .send({
341 -
      user_id: userId,
342 -
      stress_level: 3,
343 -
      anxiety_level: 4,
344 -
      energy_level: 7,
345 -
      recorded_at: now,
346 -
      mood_components: [
347 -
        { emotion: "invalid_emotion", intensity: 5 }
348 -
      ]
349 -
    });
350 -

351 -
  t.is(res.status, 400);
352 -
  t.regex(res.body.error, /Invalid emotion/);
353 -
});
354 -

355 -
test("Falha ao criar registro de humor com intensidade inválida (menor que 1)", async (t) => {
356 -
  const now = new Date().toISOString();
357 -

358 -
  const res = await request(app)
359 -
    .post("/mood")
360 -
    .send({
361 -
      user_id: userId,
362 -
      stress_level: 3,
363 -
      anxiety_level: 4,
364 -
      energy_level: 7,
365 -
      recorded_at: now,
366 -
      mood_components: [
367 -
        { emotion: "joy", intensity: 0 }
368 -
      ]
369 -
    });
370 -

371 -
  t.is(res.status, 400);
372 -
  t.regex(res.body.error, /Invalid intensity/);
373 -
});
374 -

375 -
test("Falha ao criar registro de humor com intensidade inválida (maior que 10)", async (t) => {
376 -
  const now = new Date().toISOString();
377 -

378 -
  const res = await request(app)
379 -
    .post("/mood")
380 -
    .send({
381 -
      user_id: userId,
382 -
      stress_level: 3,
383 -
      anxiety_level: 4,
384 -
      energy_level: 7,
385 -
      recorded_at: now,
386 -
      mood_components: [
387 -
        { emotion: "sad", intensity: 11 }
388 -
      ]
389 -
    });
390 -

391 -
  t.is(res.status, 400);
392 -
  t.regex(res.body.error, /Invalid intensity/);
393 -
});
394 -

395 -
test("Falha ao criar registro de humor com emoções duplicadas", async (t) => {
396 -
  const now = new Date().toISOString();
397 -

398 -
  const res = await request(app)
399 -
    .post("/mood")
400 -
    .send({
401 -
      user_id: userId,
402 -
      stress_level: 3,
403 -
      anxiety_level: 4,
404 -
      energy_level: 7,
405 -
      recorded_at: now,
406 -
      mood_components: [
407 -
        { emotion: "joy", intensity: 7 },
408 -
        { emotion: "joy", intensity: 5 }
409 -
      ]
410 -
    });
411 -

412 -
  t.is(res.status, 400);
413 -
  t.regex(res.body.error, /Duplicate emotion/);
414 -
});
415 -

416 -
test("Falha ao criar registro de humor com componente sem emoção de referencia", async (t) => {
417 -
  const now = new Date().toISOString();
418 -

419 -
  const res = await request(app)
420 -
    .post("/mood")
421 -
    .send({
422 -
      user_id: userId,
423 -
      stress_level: 3,
424 -
      anxiety_level: 4,
425 -
      energy_level: 7,
426 -
      recorded_at: now,
427 -
      mood_components: [
428 -
        { intensity: 5 }
429 -
      ]
430 -
    });
431 -

432 -
  t.is(res.status, 400);
433 -
  t.regex(res.body.error, /must have emotion and intensity/);
434 -
});
435 -

436 -
test("Falha ao criar registro de humor com componente sem intensidade", async (t) => {
437 -
  const now = new Date().toISOString();
438 -

439 -
  const res = await request(app)
440 -
    .post("/mood")
441 -
    .send({
442 -
      user_id: userId,
443 -
      stress_level: 3,
444 -
      anxiety_level: 4,
445 -
      energy_level: 7,
446 -
      recorded_at: now,
447 -
      mood_components: [
448 -
        { emotion: "joy" }
449 -
      ]
450 -
    });
451 -

452 -
  t.is(res.status, 400);
453 -
  t.regex(res.body.error, /must have emotion and intensity/);
454 -
});
455 -

456 -
test("Criar registro de humor com lista vazia de componentes deve funcionar", async (t) => {
457 -
  const now = new Date().toISOString();
458 -

459 -
  const res = await request(app)
460 -
    .post("/mood")
461 -
    .send({
462 -
      user_id: userId,
463 -
      stress_level: 3,
464 -
      anxiety_level: 4,
465 -
      energy_level: 7,
466 -
      recorded_at: now,
467 -
      mood_components: []
468 -
    });
469 -

470 -
  t.is(res.status, 201);
471 -

472 -
  // Verify no components were created
473 -
  const components = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").all(res.body.id);
474 -
  t.is(components.length, 0);
475 -
});
476 -

477 -
test("Descrição e título devem ser sanitizados (truncados em 500 caracteres)", async (t) => {
478 -
  const now = new Date().toISOString();
479 -
  const longText = "A".repeat(600);
480 -

481 -
  const res = await request(app)
482 -
    .post("/mood")
483 -
    .send({
484 -
      user_id: userId,
485 -
      stress_level: 3,
486 -
      anxiety_level: 4,
487 -
      energy_level: 7,
488 -
      recorded_at: now,
489 -
      title: longText,
490 -
      description: longText
491 -
    });
492 -

493 -
  t.is(res.status, 201);
494 -

495 -
  const mood = db.prepare("SELECT title, description FROM mood WHERE id = ?").get(res.body.id);
496 -
  t.is(mood.title.length, 500);
497 -
  t.is(mood.description.length, 500);
498 -
});
api/tests/mood/queries.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -
let userId;
9 -
let moodIds = [];
10 -

11 -
test.before(() => {
12 -
  db = setupTestDb();
13 -
  app = createApp(db);
14 -
});
15 -

16 -
test.beforeEach(async () => {
17 -
  cleanupTestDb();
18 -
  moodIds = [];
19 -

20 -
  // Create a test user with unique email
21 -
  const uniqueEmail = `mood_${Date.now()}_${Math.random()}@example.com`;
22 -
  const userRes = await request(app)
23 -
    .post("/users")
24 -
    .send({
25 -
      email: uniqueEmail,
26 -
      password: "senha123",
27 -
      first_name: "Mood",
28 -
      last_name: "Tester"
29 -
    });
30 -

31 -
  if (userRes.status !== 201) {
32 -
    throw new Error(`Failed to create test user: ${JSON.stringify(userRes.body)}`);
33 -
  }
34 -

35 -
  userId = userRes.body.id;
36 -

37 -
  // Create multiple moods for testing
38 -
  const dates = [
39 -
    new Date('2024-01-15T10:00:00Z'),
40 -
    new Date('2024-01-20T14:30:00Z'),
41 -
    new Date('2024-02-01T08:00:00Z'),
42 -
    new Date('2024-02-15T16:45:00Z'),
43 -
    new Date('2024-03-01T12:00:00Z')
44 -
  ];
45 -

46 -
  for (let i = 0; i < dates.length; i++) {
47 -
    const moodRes = await request(app)
48 -
      .post("/mood")
49 -
      .send({
50 -
        user_id: userId,
51 -
        rating: 5 + i,
52 -
        stress_level: 3 + i,
53 -
        anxiety_level: 2 + i,
54 -
        energy_level: 6 - i,
55 -
        title: `Mood ${i + 1}`,
56 -
        recorded_at: dates[i].toISOString(),
57 -
        mood_components: i % 2 === 0 ? [
58 -
          { emotion: "joy", intensity: 5 + i },
59 -
          { emotion: "trust", intensity: 4 + i }
60 -
        ] : []
61 -
      });
62 -
    moodIds.push(moodRes.body.id);
63 -
  }
64 -
});
65 -

66 -
test.serial("Obter mood específico por ID", async (t) => {
67 -
  const res = await request(app).get(`/mood/${moodIds[0]}`);
68 -

69 -
  t.is(res.status, 200);
70 -
  t.is(Number(res.body.id), Number(moodIds[0]));
71 -
  t.is(Number(res.body.user_id), Number(userId));
72 -
  t.is(res.body.title, "Mood 1");
73 -
  t.truthy(res.body.first_name);
74 -
  t.truthy(res.body.last_name);
75 -
  t.true(Array.isArray(res.body.mood_components));
76 -
});
77 -

78 -
test.serial("Mood deve incluir componentes emocionais", async (t) => {
79 -
  const res = await request(app).get(`/mood/${moodIds[0]}`);
80 -

81 -
  t.is(res.status, 200);
82 -
  t.is(res.body.mood_components.length, 2);
83 -

84 -
  const emotions = res.body.mood_components.map(c => c.emotion);
85 -
  t.true(emotions.includes('joy'));
86 -
  t.true(emotions.includes('trust'));
87 -
});
88 -

89 -
test.serial("Mood deve incluir estatísticas emocionais quando houver componentes", async (t) => {
90 -
  const res = await request(app).get(`/mood/${moodIds[0]}`);
91 -

92 -
  t.is(res.status, 200);
93 -
  t.truthy(res.body.emotion_stats);
94 -
  t.truthy(res.body.emotion_stats.dominant);
95 -
  t.truthy(res.body.emotion_stats.average);
96 -
  t.truthy(res.body.emotion_stats.breakdown);
97 -
});
98 -

99 -
test.serial("Falha ao obter mood inexistente", async (t) => {
100 -
  const res = await request(app).get("/mood/99999");
101 -

102 -
  t.is(res.status, 404);
103 -
  t.is(res.body.error, "Humor não encontrado");
104 -
});
105 -

106 -
test.serial("Obter todos os moods de um usuário", async (t) => {
107 -
  const res = await request(app).get(`/mood/user/${userId}`);
108 -

109 -
  t.is(res.status, 200);
110 -
  t.truthy(res.body.moods);
111 -
  t.is(res.body.moods.length, 5);
112 -
  t.truthy(res.body.pagination);
113 -
  t.is(res.body.pagination.total, 5);
114 -
});
115 -

116 -
test.serial("Moods devem estar ordenados por data (mais recente primeiro)", async (t) => {
117 -
  const res = await request(app).get(`/mood/user/${userId}`);
118 -

119 -
  t.is(res.status, 200);
120 -

121 -
  const dates = res.body.moods.map(m => new Date(m.recorded_at));
122 -
  for (let i = 1; i < dates.length; i++) {
123 -
    t.true(dates[i - 1] >= dates[i]);
124 -
  }
125 -
});
126 -

127 -
test.serial("Filtrar registros de humor por intervalo de datas", async (t) => {
128 -
  const res = await request(app).get(`/mood/user/${userId}`)
129 -
    .query({
130 -
      start_date: '2024-01-01',
131 -
      end_date: '2024-01-31'
132 -
    });
133 -

134 -
  t.is(res.status, 200);
135 -
  t.is(res.body.moods.length, 2); // Only January moods
136 -
});
137 -

138 -
test.serial("Filtrar registros de humor apenas por data de início", async (t) => {
139 -
  const res = await request(app).get(`/mood/user/${userId}`)
140 -
    .query({
141 -
      start_date: '2024-02-01'
142 -
    });
143 -

144 -
  t.is(res.status, 200);
145 -
  t.is(res.body.moods.length, 3); // Feb and March moods
146 -
});
147 -

148 -
test.serial("Filtrar registros de humor apenas por data de fim", async (t) => {
149 -
  const res = await request(app).get(`/mood/user/${userId}`)
150 -
    .query({
151 -
      end_date: '2024-01-31'
152 -
    });
153 -

154 -
  t.is(res.status, 200);
155 -
  t.is(res.body.moods.length, 2); // Only January moods
156 -
});
157 -

158 -
test.serial("Paginação de moods", async (t) => {
159 -
  const res = await request(app).get(`/mood/user/${userId}`)
160 -
    .query({
161 -
      page: 2,
162 -
      limit: 2
163 -
    });
164 -

165 -
  t.is(res.status, 200);
166 -
  t.is(res.body.moods.length, 2);
167 -
  t.is(res.body.pagination.page, 2);
168 -
  t.is(res.body.pagination.limit, 2);
169 -
  t.is(res.body.pagination.total_pages, 3);
170 -
});
171 -

172 -
test.serial("Paginação com limite máximo de 100", async (t) => {
173 -
  const res = await request(app).get(`/mood/user/${userId}`)
174 -
    .query({
175 -
      limit: 200
176 -
    });
177 -

178 -
  t.is(res.status, 200);
179 -
  t.is(res.body.pagination.limit, 100); // Should be capped at 100
180 -
});
181 -

182 -
test.serial("Falha ao filtrar com intervalo de datas inválido", async (t) => {
183 -
  const res = await request(app).get(`/mood/user/${userId}`)
184 -
    .query({
185 -
      start_date: '2024-02-01',
186 -
      end_date: '2024-01-01' // End before start
187 -
    });
188 -

189 -
  t.is(res.status, 400);
190 -
  t.is(res.body.error, "Intervalo de datas inválido");
191 -
});
192 -

193 -
test.serial("Falha ao filtrar com data de início inválida", async (t) => {
194 -
  const res = await request(app).get(`/mood/user/${userId}`)
195 -
    .query({
196 -
      start_date: 'data-invalida'
197 -
    });
198 -

199 -
  t.is(res.status, 400);
200 -
  t.is(res.body.error, "Data de início inválida");
201 -
});
202 -

203 -
test.serial("Falha ao filtrar com data de fim inválida", async (t) => {
204 -
  const res = await request(app).get(`/mood/user/${userId}`)
205 -
    .query({
206 -
      end_date: 'data-invalida'
207 -
    });
208 -

209 -
  t.is(res.status, 400);
210 -
  t.is(res.body.error, "Data de fim inválida");
211 -
});
212 -

213 -
test.serial("Obter estatísticas de mood do usuário", async (t) => {
214 -
  const res = await request(app).get(`/mood/user/${userId}/stats`);
215 -

216 -
  t.is(res.status, 200);
217 -
  t.truthy(res.body.overall);
218 -
  t.is(res.body.overall.total_entries, 5);
219 -
  t.truthy(res.body.overall.avg_rating);
220 -
  t.truthy(res.body.overall.avg_stress);
221 -
  t.truthy(res.body.overall.avg_anxiety);
222 -
  t.truthy(res.body.overall.avg_energy);
223 -
  t.truthy(res.body.emotions);
224 -
  t.truthy(res.body.trends);
225 -
});
226 -

227 -
test.serial("Estatísticas devem incluir frequência de emoções", async (t) => {
228 -
  const res = await request(app).get(`/mood/user/${userId}/stats`);
229 -

230 -
  t.is(res.status, 200);
231 -
  t.true(Array.isArray(res.body.emotions));
232 -

233 -
  // We created 3 moods with components
234 -
  const joyStats = res.body.emotions.find(e => e.emotion === 'joy');
235 -
  t.truthy(joyStats);
236 -
  t.is(joyStats.frequency, 3);
237 -
});
238 -

239 -
test.serial("Estatísticas com filtro de data", async (t) => {
240 -
  const res = await request(app).get(`/mood/user/${userId}/stats`)
241 -
    .query({
242 -
      start_date: '2024-01-01',
243 -
      end_date: '2024-01-31'
244 -
    });
245 -

246 -
  t.is(res.status, 200);
247 -
  t.is(res.body.overall.total_entries, 2); // Only January
248 -
  t.is(res.body.date_range.start, '2024-01-01');
249 -
  t.is(res.body.date_range.end, '2024-01-31');
250 -
});
251 -

252 -
test.serial("Estatísticas devem incluir tendências por dia da semana", async (t) => {
253 -
  const res = await request(app).get(`/mood/user/${userId}/stats`);
254 -

255 -
  t.is(res.status, 200);
256 -
  t.true(Array.isArray(res.body.trends.by_day_of_week));
257 -

258 -
  const hasDay = res.body.trends.by_day_of_week.some(d =>
259 -
    ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'].includes(d.day_of_week)
260 -
  );
261 -
  t.true(hasDay);
262 -
});
263 -

264 -
test.serial("Usuário sem moods deve retornar lista vazia", async (t) => {
265 -
  // Create another user without moods
266 -
  const newUserRes = await request(app)
267 -
    .post("/users")
268 -
    .send({
269 -
      email: "nomood@example.com",
270 -
      password: "senha123",
271 -
      first_name: "No",
272 -
      last_name: "Mood"
273 -
    });
274 -

275 -
  const res = await request(app).get(`/mood/user/${newUserRes.body.id}`);
276 -

277 -
  t.is(res.status, 200);
278 -
  t.is(res.body.moods.length, 0);
279 -
  t.is(res.body.pagination.total, 0);
280 -
});
281 -

282 -
test.serial("Estatísticas de usuário sem moods", async (t) => {
283 -
  // Create another user without moods
284 -
  const newUserRes = await request(app)
285 -
    .post("/users")
286 -
    .send({
287 -
      email: "nostats@example.com",
288 -
      password: "senha123",
289 -
      first_name: "No",
290 -
      last_name: "Stats"
291 -
    });
292 -

293 -
  const res = await request(app).get(`/mood/user/${newUserRes.body.id}/stats`);
294 -

295 -
  t.is(res.status, 200);
296 -
  t.is(res.body.overall.total_entries, 0);
297 -
  t.is(res.body.emotions.length, 0);
298 -
});
api/tests/mood/updates.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -
let userId;
9 -
let moodId;
10 -

11 -
test.before(() => {
12 -
  db = setupTestDb();
13 -
  app = createApp(db);
14 -
});
15 -

16 -
test.beforeEach(async () => {
17 -
  cleanupTestDb();
18 -

19 -
  // Create a test user with unique email
20 -
  const uniqueEmail = `mood_${Date.now()}_${Math.random()}@example.com`;
21 -
  const userRes = await request(app)
22 -
    .post("/users")
23 -
    .send({
24 -
      email: uniqueEmail,
25 -
      password: "senha123",
26 -
      first_name: "Mood",
27 -
      last_name: "Tester"
28 -
    });
29 -

30 -
  if (userRes.status !== 201) {
31 -
    throw new Error(`Failed to create test user: ${JSON.stringify(userRes.body)}`);
32 -
  }
33 -

34 -
  userId = userRes.body.id;
35 -

36 -
  // Create a mood to update
37 -
  const moodRes = await request(app)
38 -
    .post("/mood")
39 -
    .send({
40 -
      user_id: userId,
41 -
      rating: 5,
42 -
      stress_level: 4,
43 -
      anxiety_level: 3,
44 -
      energy_level: 7,
45 -
      title: "Original mood",
46 -
      description: "Original description",
47 -
      recorded_at: new Date().toISOString(),
48 -
      mood_components: [
49 -
        { emotion: "joy", intensity: 6 },
50 -
        { emotion: "trust", intensity: 7 }
51 -
      ]
52 -
    });
53 -

54 -
  moodId = moodRes.body.id;
55 -
});
56 -

57 -
test.serial("Atualizar rating do mood", async (t) => {
58 -
  const res = await request(app)
59 -
    .put(`/mood/${moodId}`)
60 -
    .send({
61 -
      rating: 8
62 -
    });
63 -

64 -
  t.is(res.status, 200);
65 -
  t.true(res.body.success);
66 -

67 -
  // Verify update
68 -
  const mood = db.prepare("SELECT rating FROM mood WHERE id = ?").get(moodId);
69 -
  t.is(mood.rating, 8);
70 -
});
71 -

72 -
test.serial("Atualizar múltiplos níveis do mood", async (t) => {
73 -
  const res = await request(app)
74 -
    .put(`/mood/${moodId}`)
75 -
    .send({
76 -
      stress_level: 2,
77 -
      anxiety_level: 1,
78 -
      energy_level: 9
79 -
    });
80 -

81 -
  t.is(res.status, 200);
82 -
  t.true(res.body.success);
83 -

84 -
  // Verify updates
85 -
  const mood = db.prepare("SELECT stress_level, anxiety_level, energy_level FROM mood WHERE id = ?").get(moodId);
86 -
  t.is(mood.stress_level, 2);
87 -
  t.is(mood.anxiety_level, 1);
88 -
  t.is(mood.energy_level, 9);
89 -
});
90 -

91 -
test.serial("Atualizar título e descrição do mood", async (t) => {
92 -
  const res = await request(app)
93 -
    .put(`/mood/${moodId}`)
94 -
    .send({
95 -
      title: "Novo título",
96 -
      description: "Nova descrição detalhada"
97 -
    });
98 -

99 -
  t.is(res.status, 200);
100 -
  t.true(res.body.success);
101 -

102 -
  // Verify updates
103 -
  const mood = db.prepare("SELECT title, description FROM mood WHERE id = ?").get(moodId);
104 -
  t.is(mood.title, "Novo título");
105 -
  t.is(mood.description, "Nova descrição detalhada");
106 -
});
107 -

108 -
test.serial("Atualizar data do mood", async (t) => {
109 -
  const newDate = new Date('2024-01-15T10:00:00Z');
110 -

111 -
  const res = await request(app)
112 -
    .put(`/mood/${moodId}`)
113 -
    .send({
114 -
      recorded_at: newDate.toISOString()
115 -
    });
116 -

117 -
  t.is(res.status, 200);
118 -
  t.true(res.body.success);
119 -

120 -
  // Verify update
121 -
  const mood = db.prepare("SELECT recorded_at FROM mood WHERE id = ?").get(moodId);
122 -
  t.truthy(mood.recorded_at.includes('2024-01-15'));
123 -
});
124 -

125 -
test.serial("Atualizar componentes emocionais do mood", async (t) => {
126 -
  const res = await request(app)
127 -
    .put(`/mood/${moodId}`)
128 -
    .send({
129 -
      mood_components: [
130 -
        { emotion: "sad", intensity: 4 },
131 -
        { emotion: "fear", intensity: 3 },
132 -
        { emotion: "angry", intensity: 2 }
133 -
      ]
134 -
    });
135 -

136 -
  t.is(res.status, 200);
137 -
  t.true(res.body.success);
138 -

139 -
  // Verify old components were replaced
140 -
  const components = db.prepare("SELECT emotion, intensity FROM mood_components WHERE mood_id = ? ORDER BY emotion").all(moodId);
141 -
  t.is(components.length, 3);
142 -

143 -
  const emotions = components.map(c => c.emotion);
144 -
  t.true(emotions.includes('sad'));
145 -
  t.true(emotions.includes('fear'));
146 -
  t.true(emotions.includes('angry'));
147 -
  t.false(emotions.includes('joy')); // Old emotion should be gone
148 -
  t.false(emotions.includes('trust')); // Old emotion should be gone
149 -
});
150 -

151 -
test.serial("Remover todos os componentes emocionais enviando array vazio", async (t) => {
152 -
  const res = await request(app)
153 -
    .put(`/mood/${moodId}`)
154 -
    .send({
155 -
      mood_components: []
156 -
    });
157 -

158 -
  t.is(res.status, 200);
159 -
  t.true(res.body.success);
160 -

161 -
  // Verify components were deleted
162 -
  const components = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").all(moodId);
163 -
  t.is(components.length, 0);
164 -
});
165 -

166 -
test.serial("Atualização deve modificar a coluna de atualização", async (t) => {
167 -
  // Get original updated_at
168 -
  const originalMood = db.prepare("SELECT updated_at FROM mood WHERE id = ?")
169 -
    .get(moodId);
170 -

171 -
  // Wait a bit to ensure timestamp difference
172 -
  await new Promise(resolve => setTimeout(resolve, 1100));
173 -

174 -
  const res = await request(app)
175 -
    .put(`/mood/${moodId}`)
176 -
    .send({
177 -
      rating: 9
178 -
    });
179 -

180 -
  t.is(res.status, 200);
181 -

182 -
  // Verify updated_at changed
183 -
  const updatedMood = db.prepare("SELECT updated_at FROM mood WHERE id = ?")
184 -
    .get(moodId);
185 -

186 -
  t.not(updatedMood.updated_at, originalMood.updated_at);
187 -
});
188 -

189 -
test.serial("Falha ao atualizar humor inexistente", async (t) => {
190 -
  const res = await request(app)
191 -
    .put("/mood/99999")
192 -
    .send({
193 -
      rating: 8
194 -
    });
195 -

196 -
  t.is(res.status, 404);
197 -
  t.is(res.body.error, "Humor não encontrado");
198 -
});
199 -

200 -
test.serial("Falha ao atualizar com avaliação inválida", async (t) => {
201 -
  const res = await request(app)
202 -
    .put(`/mood/${moodId}`)
203 -
    .send({
204 -
      rating: 15
205 -
    });
206 -

207 -
  t.is(res.status, 400);
208 -
  t.is(res.body.error, "rating deve ser entre 1 e 10");
209 -
});
210 -

211 -
test.serial("Falha ao atualizar com nível de estresse inválido", async (t) => {
212 -
  const res = await request(app)
213 -
    .put(`/mood/${moodId}`)
214 -
    .send({
215 -
      stress_level: 0
216 -
    });
217 -

218 -
  t.is(res.status, 400);
219 -
  t.is(res.body.error, "stress_level deve ser entre 1 e 10");
220 -
});
221 -

222 -
test.serial("Falha ao atualizar com nível de ansiedade inválido", async (t) => {
223 -
  const res = await request(app)
224 -
    .put(`/mood/${moodId}`)
225 -
    .send({
226 -
      anxiety_level: 11
227 -
    });
228 -

229 -
  t.is(res.status, 400);
230 -
  t.is(res.body.error, "anxiety_level deve ser entre 1 e 10");
231 -
});
232 -

233 -
test.serial("Falha ao atualizar com nível de energia inválida", async (t) => {
234 -
  const res = await request(app)
235 -
    .put(`/mood/${moodId}`)
236 -
    .send({
237 -
      energy_level: -1
238 -
    });
239 -

240 -
  t.is(res.status, 400);
241 -
  t.is(res.body.error, "energy_level deve ser entre 1 e 10");
242 -
});
243 -

244 -
test.serial("Falha ao atualizar com data inválida", async (t) => {
245 -
  const res = await request(app)
246 -
    .put(`/mood/${moodId}`)
247 -
    .send({
248 -
      recorded_at: "data-invalida"
249 -
    });
250 -

251 -
  t.is(res.status, 400);
252 -
  t.is(res.body.error, "recorded_at deve ser uma data válida");
253 -
});
254 -

255 -
test.serial("Falha ao atualizar com data no futuro", async (t) => {
256 -
  const futureDate = new Date();
257 -
  futureDate.setDate(futureDate.getDate() + 1);
258 -

259 -
  const res = await request(app)
260 -
    .put(`/mood/${moodId}`)
261 -
    .send({
262 -
      recorded_at: futureDate.toISOString()
263 -
    });
264 -

265 -
  t.is(res.status, 400);
266 -
  t.is(res.body.error, "recorded_at não pode ser no futuro");
267 -
});
268 -

269 -
test.serial("Falha ao atualizar com emoção inválida nos componentes", async (t) => {
270 -
  const res = await request(app)
271 -
    .put(`/mood/${moodId}`)
272 -
    .send({
273 -
      mood_components: [
274 -
        { emotion: "invalid", intensity: 5 }
275 -
      ]
276 -
    });
277 -

278 -
  t.is(res.status, 400);
279 -
  t.regex(res.body.error, /Invalid emotion/);
280 -
});
281 -

282 -
test.serial("Falha ao atualizar com emoções duplicadas", async (t) => {
283 -
  const res = await request(app)
284 -
    .put(`/mood/${moodId}`)
285 -
    .send({
286 -
      mood_components: [
287 -
        { emotion: "joy", intensity: 5 },
288 -
        { emotion: "joy", intensity: 7 }
289 -
      ]
290 -
    });
291 -

292 -
  t.is(res.status, 400);
293 -
  t.regex(res.body.error, /Duplicate emotion/);
294 -
});
295 -

296 -
test.serial("Deletar humor existente", async (t) => {
297 -
  const res = await request(app).delete(`/mood/${moodId}`);
298 -

299 -
  t.is(res.status, 200);
300 -
  t.true(res.body.success);
301 -
  t.is(Number(res.body.deleted), Number(moodId));
302 -

303 -
  // Verify mood is deleted
304 -
  const mood = db.prepare("SELECT * FROM mood WHERE id = ?").get(moodId);
305 -
  t.falsy(mood);
306 -
});
307 -

308 -
test.serial("Deletar humor deve deletar seus componentes (em cascata)", async (t) => {
309 -
  // Verify components exist
310 -
  const componentsBefore = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").all(moodId);
311 -
  t.true(componentsBefore.length > 0);
312 -

313 -
  const res = await request(app).delete(`/mood/${moodId}`);
314 -
  t.is(res.status, 200);
315 -

316 -
  // Verify components are deleted
317 -
  const componentsAfter = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").all(moodId);
318 -
  t.is(componentsAfter.length, 0);
319 -
});
320 -

321 -
test.serial("Falha ao deletar mood inexistente", async (t) => {
322 -
  const res = await request(app).delete("/mood/99999");
323 -

324 -
  t.is(res.status, 404);
325 -
  t.is(res.body.error, "Humor não encontrado");
326 -
});
327 -

328 -
test.serial("Atualização parcial mantém valores não alterados", async (t) => {
329 -
  // Get original values
330 -
  const originalMood = db.prepare("SELECT * FROM mood WHERE id = ?").get(moodId);
331 -

332 -
  // Update only rating
333 -
  const res = await request(app)
334 -
    .put(`/mood/${moodId}`)
335 -
    .send({
336 -
      rating: 10
337 -
    });
338 -

339 -
  t.is(res.status, 200);
340 -

341 -
  // Verify only rating changed, others remained
342 -
  const updatedMood = db.prepare("SELECT * FROM mood WHERE id = ?").get(moodId);
343 -
  t.is(updatedMood.rating, 10);
344 -
  t.is(updatedMood.stress_level, originalMood.stress_level);
345 -
  t.is(updatedMood.anxiety_level, originalMood.anxiety_level);
346 -
  t.is(updatedMood.energy_level, originalMood.energy_level);
347 -
  t.is(updatedMood.title, originalMood.title);
348 -
  t.is(updatedMood.description, originalMood.description);
349 -
});
api/tests/test-helper.js → /dev/null
1 -
import { setupTestDatabase } from '../src/setup-db.js';
2 -

3 -
// Store a single test database instance
4 -
let globalTestDb = null;
5 -

6 -
// Setup the test database
7 -
export function setupTestDb() {
8 -
  if (!globalTestDb) {
9 -
    globalTestDb = setupTestDatabase();
10 -
  }
11 -
  return globalTestDb;
12 -
}
13 -

14 -
// Get the test database
15 -
export function getTestDb() {
16 -
  return globalTestDb;
17 -
}
18 -

19 -
// Cleanup test database
20 -
export function cleanupTestDb() {
21 -
  if (globalTestDb) {
22 -
    try {
23 -
      // Delete in correct order due to foreign keys
24 -
      globalTestDb.exec(`
25 -
        DELETE FROM mood_components;
26 -
        DELETE FROM mood;
27 -
        DELETE FROM users;
28 -
      `);
29 -
    } catch (err) {
30 -
      console.error('Error cleaning test DB:', err);
31 -
    }
32 -
  }
33 -
}
/dev/null → api/tests/test-helper.ts
1 +
import { PrismaClient } from '@prisma/client';
2 +
import { PrismaPg } from '@prisma/adapter-pg';
3 +
import 'dotenv/config';
4 +

5 +
let prismaTestClient: PrismaClient | null = null;
6 +

7 +
export function getTestPrisma(): PrismaClient {
8 +
  if (!prismaTestClient) {
9 +
    // Use test database URL
10 +
    const connectionString = process.env.DATABASE_URL || 'postgres://user:password@localhost:5430/orbit_test';
11 +
    const adapter = new PrismaPg({ connectionString });
12 +
    prismaTestClient = new PrismaClient({ adapter });
13 +
  }
14 +
  return prismaTestClient;
15 +
}
16 +

17 +
export async function cleanupTestDb() {
18 +
  const prisma = getTestPrisma();
19 +

20 +
  // Delete in correct order due to foreign keys
21 +
  // Add more tables as they're added to schema
22 +
  try {
23 +
    // When we add more models, delete them here in reverse order of dependencies
24 +
    await prisma.user.deleteMany({});
25 +
  } catch (err) {
26 +
    console.error('Error cleaning test DB:', err);
27 +
  }
28 +
}
29 +

30 +
export async function disconnectTestDb() {
31 +
  if (prismaTestClient) {
32 +
    await prismaTestClient.$disconnect();
33 +
    prismaTestClient = null;
34 +
  }
35 +
}
36 +

37 +
// Helper to create test users
38 +
export async function createTestUser(data?: {
39 +
  email?: string;
40 +
  firstName?: string;
41 +
  lastName?: string;
42 +
  encryptedPassword?: string;
43 +
}) {
44 +
  const prisma = getTestPrisma();
45 +
  return await prisma.user.create({
46 +
    data: {
47 +
      email: data?.email || 'test@example.com',
48 +
      firstName: data?.firstName || 'Test',
49 +
      lastName: data?.lastName || 'User',
50 +
      encryptedPassword: data?.encryptedPassword || '$2a$10$test'
51 +
    }
52 +
  });
53 +
}
api/tests/users.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "./test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -

9 -
test.before(() => {
10 -
  db = setupTestDb();
11 -
  app = createApp(db);
12 -
});
13 -

14 -
test.beforeEach(() => {
15 -
  cleanupTestDb();
16 -
});
17 -

18 -
test("Criar usuário", async (t) => {
19 -
  const res = await request(app)
20 -
    .post("/users")
21 -
    .send({
22 -
      email: "john@example.com",
23 -
      password: "123456",
24 -
      first_name: "John",
25 -
      last_name: "Doe",
26 -
    });
27 -

28 -
  t.is(res.status, 201);
29 -
  t.truthy(res.body.id);
30 -
});
31 -

32 -
test("Falha ao criar usuário sem email", async (t) => {
33 -
  const res = await request(app)
34 -
    .post("/users")
35 -
    .send({
36 -
      password: "123456",
37 -
      first_name: "John",
38 -
      last_name: "Doe",
39 -
    });
40 -

41 -
  t.is(res.status, 400);
42 -
  t.is(res.body.error, "Campos faltantes");
43 -
});
44 -

45 -
test("Falha ao criar usuário com email duplicado", async (t) => {
46 -
  // First user
47 -
  await request(app)
48 -
    .post("/users")
49 -
    .send({
50 -
      email: "duplicate@example.com",
51 -
      password: "123456",
52 -
      first_name: "John",
53 -
      last_name: "Doe",
54 -
    });
55 -

56 -
  // Duplicate email
57 -
  const res = await request(app)
58 -
    .post("/users")
59 -
    .send({
60 -
      email: "duplicate@example.com",
61 -
      password: "123456",
62 -
      first_name: "Jane",
63 -
      last_name: "Smith",
64 -
    });
65 -

66 -
  t.is(res.status, 400);
67 -
  t.is(res.body.error, "Email já cadastrado");
68 -
});
api/tests/users/authentication.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import bcrypt from "bcryptjs";
4 -
import { createApp } from "../../src/create-app.js";
5 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
6 -

7 -
let app;
8 -
let db;
9 -

10 -
test.before(() => {
11 -
  db = setupTestDb();
12 -
  app = createApp(db);
13 -
});
14 -

15 -
test.beforeEach(() => {
16 -
  cleanupTestDb();
17 -

18 -
  // Create a test user for login tests
19 -
  const hashedPassword = bcrypt.hashSync("senha123", 10);
20 -
  db.prepare(`
21 -
    INSERT INTO users (email, password, first_name, last_name, timezone)
22 -
    VALUES (?, ?, ?, ?, ?)
23 -
  `).run("teste@example.com", hashedPassword, "Teste", "User", "UTC");
24 -
});
25 -

26 -
test("Login bem-sucedido com credenciais corretas", async (t) => {
27 -
  const res = await request(app)
28 -
    .post("/users/login")
29 -
    .send({
30 -
      email: "teste@example.com",
31 -
      password: "senha123"
32 -
    });
33 -

34 -
  t.is(res.status, 200);
35 -
  t.true(res.body.success);
36 -
  t.truthy(res.body.user);
37 -
  t.is(res.body.user.email, "teste@example.com");
38 -
  t.is(res.body.user.first_name, "Teste");
39 -
  t.is(res.body.user.last_name, "User");
40 -
  t.falsy(res.body.user.password); // Password should not be in response
41 -
});
42 -

43 -
test("Login com email em maiúsculas deve funcionar", async (t) => {
44 -
  const res = await request(app)
45 -
    .post("/users/login")
46 -
    .send({
47 -
      email: "TESTE@EXAMPLE.COM",
48 -
      password: "senha123"
49 -
    });
50 -

51 -
  t.is(res.status, 200);
52 -
  t.true(res.body.success);
53 -
});
54 -

55 -
test("Falha no login com senha incorreta", async (t) => {
56 -
  const res = await request(app)
57 -
    .post("/users/login")
58 -
    .send({
59 -
      email: "teste@example.com",
60 -
      password: "senhaerrada"
61 -
    });
62 -

63 -
  t.is(res.status, 401);
64 -
  t.is(res.body.error, "Credenciais inválidas");
65 -
});
66 -

67 -
test("Falha no login com email não cadastrado", async (t) => {
68 -
  const res = await request(app)
69 -
    .post("/users/login")
70 -
    .send({
71 -
      email: "naocadastrado@example.com",
72 -
      password: "senha123"
73 -
    });
74 -

75 -
  t.is(res.status, 401);
76 -
  t.is(res.body.error, "Credenciais inválidas");
77 -
});
78 -

79 -
test("Falha no login sem email", async (t) => {
80 -
  const res = await request(app)
81 -
    .post("/users/login")
82 -
    .send({
83 -
      password: "senha123"
84 -
    });
85 -

86 -
  t.is(res.status, 400);
87 -
  t.is(res.body.error, "Email e senha são obrigatórios");
88 -
});
89 -

90 -
test("Falha no login sem senha", async (t) => {
91 -
  const res = await request(app)
92 -
    .post("/users/login")
93 -
    .send({
94 -
      email: "teste@example.com"
95 -
    });
96 -

97 -
  t.is(res.status, 400);
98 -
  t.is(res.body.error, "Email e senha são obrigatórios");
99 -
});
100 -

101 -
test("Falha no login sem credenciais", async (t) => {
102 -
  const res = await request(app)
103 -
    .post("/users/login")
104 -
    .send({});
105 -

106 -
  t.is(res.status, 400);
107 -
  t.is(res.body.error, "Email e senha são obrigatórios");
108 -
});
109 -

110 -
test("Login não deve retornar a senha do usuário", async (t) => {
111 -
  const res = await request(app)
112 -
    .post("/users/login")
113 -
    .send({
114 -
      email: "teste@example.com",
115 -
      password: "senha123"
116 -
    });
117 -

118 -
  t.is(res.status, 200);
119 -
  t.falsy(res.body.user.password);
120 -
  t.is(typeof res.body.user.password, 'undefined');
121 -
});
122 -

123 -
test("Login deve retornar informações completas do usuário", async (t) => {
124 -
  const res = await request(app)
125 -
    .post("/users/login")
126 -
    .send({
127 -
      email: "teste@example.com",
128 -
      password: "senha123"
129 -
    });
130 -

131 -
  t.is(res.status, 200);
132 -
  t.truthy(res.body.user.id);
133 -
  t.is(res.body.user.email, "teste@example.com");
134 -
  t.is(res.body.user.first_name, "Teste");
135 -
  t.is(res.body.user.last_name, "User");
136 -
  t.is(res.body.user.timezone, "UTC");
137 -
});
138 -

139 -
test("Login com espaços em branco deve ser tratado corretamente", async (t) => {
140 -
  const res = await request(app)
141 -
    .post("/users/login")
142 -
    .send({
143 -
      email: "  teste@example.com  ",
144 -
      password: "senha123"
145 -
    });
146 -

147 -
  t.is(res.status, 401); // Should fail as email with spaces doesn't match
148 -
});
api/tests/users/creation.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -

9 -
test.before(() => {
10 -
  db = setupTestDb();
11 -
  app = createApp(db);
12 -
});
13 -

14 -
test.beforeEach(() => {
15 -
  cleanupTestDb();
16 -
});
17 -

18 -
test("Criar usuário com todos os campos válidos", async (t) => {
19 -
  const res = await request(app)
20 -
    .post("/users")
21 -
    .send({
22 -
      email: "usuario@example.com",
23 -
      password: "senha123",
24 -
      first_name: "João",
25 -
      last_name: "Silva",
26 -
      timezone: "America/Sao_Paulo"
27 -
    });
28 -

29 -
  t.is(res.status, 201);
30 -
  t.truthy(res.body.id);
31 -
});
32 -

33 -
test("Criar usuário com timezone padrão (UTC)", async (t) => {
34 -
  const res = await request(app)
35 -
    .post("/users")
36 -
    .send({
37 -
      email: "utc@example.com",
38 -
      password: "senha123",
39 -
      first_name: "Maria",
40 -
      last_name: "Santos"
41 -
    });
42 -

43 -
  t.is(res.status, 201);
44 -

45 -
  // Verify timezone was set to UTC
46 -
  const user = db.prepare("SELECT timezone FROM users WHERE id = ?").get(res.body.id);
47 -
  t.is(user.timezone, 'UTC');
48 -
});
49 -

50 -
test("Falha ao criar usuário sem email", async (t) => {
51 -
  const res = await request(app)
52 -
    .post("/users")
53 -
    .send({
54 -
      password: "senha123",
55 -
      first_name: "João",
56 -
      last_name: "Silva"
57 -
    });
58 -

59 -
  t.is(res.status, 400);
60 -
  t.is(res.body.error, "Campos faltantes");
61 -
  t.true(res.body.missing.includes('email'));
62 -
});
63 -

64 -
test("Falha ao criar usuário sem senha", async (t) => {
65 -
  const res = await request(app)
66 -
    .post("/users")
67 -
    .send({
68 -
      email: "usuario@example.com",
69 -
      first_name: "João",
70 -
      last_name: "Silva"
71 -
    });
72 -

73 -
  t.is(res.status, 400);
74 -
  t.is(res.body.error, "Campos faltantes");
75 -
  t.true(res.body.missing.includes('password'));
76 -
});
77 -

78 -
test("Falha ao criar usuário sem primeiro nome", async (t) => {
79 -
  const res = await request(app)
80 -
    .post("/users")
81 -
    .send({
82 -
      email: "usuario@example.com",
83 -
      password: "senha123",
84 -
      last_name: "Silva"
85 -
    });
86 -

87 -
  t.is(res.status, 400);
88 -
  t.is(res.body.error, "Campos faltantes");
89 -
  t.true(res.body.missing.includes('first_name'));
90 -
});
91 -

92 -
test("Falha ao criar usuário sem último nome", async (t) => {
93 -
  const res = await request(app)
94 -
    .post("/users")
95 -
    .send({
96 -
      email: "usuario@example.com",
97 -
      password: "senha123",
98 -
      first_name: "João"
99 -
    });
100 -

101 -
  t.is(res.status, 400);
102 -
  t.is(res.body.error, "Campos faltantes");
103 -
  t.true(res.body.missing.includes('last_name'));
104 -
});
105 -

106 -
test("Falha ao criar usuário com múltiplos campos faltantes", async (t) => {
107 -
  const res = await request(app)
108 -
    .post("/users")
109 -
    .send({
110 -
      first_name: "João"
111 -
    });
112 -

113 -
  t.is(res.status, 400);
114 -
  t.is(res.body.error, "Campos faltantes");
115 -
  t.true(res.body.missing.includes('email'));
116 -
  t.true(res.body.missing.includes('password'));
117 -
  t.true(res.body.missing.includes('last_name'));
118 -
});
119 -

120 -
test("Falha ao criar usuário com email inválido (sem @)", async (t) => {
121 -
  const res = await request(app)
122 -
    .post("/users")
123 -
    .send({
124 -
      email: "emailinvalido",
125 -
      password: "senha123",
126 -
      first_name: "João",
127 -
      last_name: "Silva"
128 -
    });
129 -

130 -
  t.is(res.status, 400);
131 -
  t.is(res.body.error, "Email inválido");
132 -
});
133 -

134 -
test("Falha ao criar usuário com email inválido (sem domínio)", async (t) => {
135 -
  const res = await request(app)
136 -
    .post("/users")
137 -
    .send({
138 -
      email: "usuario@",
139 -
      password: "senha123",
140 -
      first_name: "João",
141 -
      last_name: "Silva"
142 -
    });
143 -

144 -
  t.is(res.status, 400);
145 -
  t.is(res.body.error, "Email inválido");
146 -
});
147 -

148 -
test("Falha ao criar usuário com email inválido (formato incorreto)", async (t) => {
149 -
  const res = await request(app)
150 -
    .post("/users")
151 -
    .send({
152 -
      email: "@example.com",
153 -
      password: "senha123",
154 -
      first_name: "João",
155 -
      last_name: "Silva"
156 -
    });
157 -

158 -
  t.is(res.status, 400);
159 -
  t.is(res.body.error, "Email inválido");
160 -
});
161 -

162 -
test("Falha ao criar usuário com senha muito curta (menos de 6 caracteres)", async (t) => {
163 -
  const res = await request(app)
164 -
    .post("/users")
165 -
    .send({
166 -
      email: "usuario@example.com",
167 -
      password: "123",
168 -
      first_name: "João",
169 -
      last_name: "Silva"
170 -
    });
171 -

172 -
  t.is(res.status, 400);
173 -
  t.is(res.body.error, "Senha deve ter pelo menos 6 caracteres");
174 -
});
175 -

176 -
test("Falha ao criar usuário com senha vazia", async (t) => {
177 -
  const res = await request(app)
178 -
    .post("/users")
179 -
    .send({
180 -
      email: "usuario@example.com",
181 -
      password: "",
182 -
      first_name: "João",
183 -
      last_name: "Silva"
184 -
    });
185 -

186 -
  t.is(res.status, 400);
187 -
  t.is(res.body.error, "Campos faltantes");
188 -
});
189 -

190 -
test("Falha ao criar usuário com email duplicado", async (t) => {
191 -
  // Create first user
192 -
  await request(app)
193 -
    .post("/users")
194 -
    .send({
195 -
      email: "duplicado@example.com",
196 -
      password: "senha123",
197 -
      first_name: "João",
198 -
      last_name: "Silva"
199 -
    });
200 -

201 -
  // Try to create with same email
202 -
  const res = await request(app)
203 -
    .post("/users")
204 -
    .send({
205 -
      email: "duplicado@example.com",
206 -
      password: "outrasenha",
207 -
      first_name: "Maria",
208 -
      last_name: "Santos"
209 -
    });
210 -

211 -
  t.is(res.status, 400);
212 -
  t.is(res.body.error, "Email já cadastrado");
213 -
});
214 -

215 -
test("Email deve ser case-insensitive para duplicação", async (t) => {
216 -
  // Create with lowercase
217 -
  await request(app)
218 -
    .post("/users")
219 -
    .send({
220 -
      email: "usuario@example.com",
221 -
      password: "senha123",
222 -
      first_name: "João",
223 -
      last_name: "Silva"
224 -
    });
225 -

226 -
  // Try with uppercase
227 -
  const res = await request(app)
228 -
    .post("/users")
229 -
    .send({
230 -
      email: "USUARIO@EXAMPLE.COM",
231 -
      password: "senha123",
232 -
      first_name: "Maria",
233 -
      last_name: "Santos"
234 -
    });
235 -

236 -
  t.is(res.status, 400);
237 -
  t.is(res.body.error, "Email já cadastrado");
238 -
});
239 -

240 -
test("Sanitização de strings longas no nome", async (t) => {
241 -
  const longName = "A".repeat(600); // 600 characters
242 -

243 -
  const res = await request(app)
244 -
    .post("/users")
245 -
    .send({
246 -
      email: "longname@example.com",
247 -
      password: "senha123",
248 -
      first_name: longName,
249 -
      last_name: longName
250 -
    });
251 -

252 -
  t.is(res.status, 201);
253 -

254 -
  // Check that name was truncated to 500 chars
255 -
  const user = db.prepare("SELECT first_name, last_name FROM users WHERE id = ?").get(res.body.id);
256 -
  t.is(user.first_name.length, 500);
257 -
  t.is(user.last_name.length, 500);
258 -
});
api/tests/users/profile.test.js → /dev/null
1 -
import test from "ava";
2 -
import request from "supertest";
3 -
import { createApp } from "../../src/create-app.js";
4 -
import { setupTestDb, cleanupTestDb } from "../test-helper.js";
5 -

6 -
let app;
7 -
let db;
8 -
let userId;
9 -

10 -
test.before(() => {
11 -
  db = setupTestDb();
12 -
  app = createApp(db);
13 -
});
14 -

15 -
let testEmail;
16 -

17 -
test.serial.beforeEach(async () => {
18 -
  cleanupTestDb();
19 -

20 -
  // Create a test user with unique email
21 -
  testEmail = `perfil_${Date.now()}_${Math.random()}@example.com`;
22 -
  const res = await request(app)
23 -
    .post("/users")
24 -
    .send({
25 -
      email: testEmail,
26 -
      password: "senha123",
27 -
      first_name: "Perfil",
28 -
      last_name: "Teste",
29 -
      timezone: "America/Sao_Paulo"
30 -
    });
31 -

32 -
  if (res.status !== 201) {
33 -
    throw new Error(`Failed to create test user: ${JSON.stringify(res.body)}`);
34 -
  }
35 -

36 -
  userId = res.body.id;
37 -
});
38 -

39 -
test.serial("Obter perfil de usuário existente", async (t) => {
40 -
  const res = await request(app).get(`/users/${userId}`);
41 -

42 -
  t.is(res.status, 200);
43 -
  t.is(Number(res.body.id), Number(userId));
44 -
  t.is(res.body.email, testEmail);
45 -
  t.is(res.body.first_name, "Perfil");
46 -
  t.is(res.body.last_name, "Teste");
47 -
  t.is(res.body.timezone, "America/Sao_Paulo");
48 -
  t.truthy(res.body.created_at);
49 -
  t.truthy(res.body.updated_at);
50 -
  t.is(typeof res.body.total_moods, 'number');
51 -
  t.falsy(res.body.password); // Should not include password
52 -
});
53 -

54 -
test.serial("Perfil deve incluir contagem de registros de humor", async (t) => {
55 -
  // Add some moods
56 -
  const now = new Date().toISOString();
57 -

58 -
  await db.prepare(`
59 -
    INSERT INTO mood (user_id, rating, stress_level, anxiety_level, energy_level, recorded_at)
60 -
    VALUES (?, ?, ?, ?, ?, ?)
61 -
  `).run(userId, 7, 3, 4, 8, now);
62 -

63 -
  await db.prepare(`
64 -
    INSERT INTO mood (user_id, rating, stress_level, anxiety_level, energy_level, recorded_at)
65 -
    VALUES (?, ?, ?, ?, ?, ?)
66 -
  `).run(userId, 5, 6, 7, 4, now);
67 -

68 -
  const res = await request(app).get(`/users/${userId}`);
69 -

70 -
  t.is(res.status, 200);
71 -
  t.is(res.body.total_moods, 2);
72 -
});
73 -

74 -
test.serial("Falha ao obter perfil de usuário inexistente", async (t) => {
75 -
  const res = await request(app).get("/users/99999");
76 -

77 -
  t.is(res.status, 404);
78 -
  t.is(res.body.error, "Usuário não encontrado");
79 -
});
80 -

81 -
test.serial("Atualizar email do usuário", async (t) => {
82 -
  const res = await request(app)
83 -
    .put(`/users/${userId}`)
84 -
    .send({
85 -
      email: "novoemail@example.com"
86 -
    });
87 -

88 -
  t.is(res.status, 200);
89 -
  t.true(res.body.success);
90 -

91 -
  // Verify update
92 -
  const user = db.prepare("SELECT email FROM users WHERE id = ?").get(userId);
93 -
  t.is(user.email, "novoemail@example.com");
94 -
});
95 -

96 -
test.serial("Atualizar senha do usuário", async (t) => {
97 -
  const res = await request(app)
98 -
    .put(`/users/${userId}`)
99 -
    .send({
100 -
      password: "novasenha123"
101 -
    });
102 -

103 -
  t.is(res.status, 200);
104 -
  t.true(res.body.success);
105 -

106 -
  // Verify can login with new password
107 -
  const loginRes = await request(app)
108 -
    .post("/users/login")
109 -
    .send({
110 -
      email: testEmail,
111 -
      password: "novasenha123"
112 -
    });
113 -

114 -
  t.is(loginRes.status, 200);
115 -
});
116 -

117 -
test.serial("Atualizar múltiplos campos do usuário", async (t) => {
118 -
  const res = await request(app)
119 -
    .put(`/users/${userId}`)
120 -
    .send({
121 -
      first_name: "NovoNome",
122 -
      last_name: "NovoSobrenome",
123 -
      timezone: "Europe/London"
124 -
    });
125 -

126 -
  t.is(res.status, 200);
127 -
  t.true(res.body.success);
128 -

129 -
  // Verify updates
130 -
  const user = db.prepare("SELECT * FROM users WHERE id = ?").get(userId);
131 -
  t.is(user.first_name, "NovoNome");
132 -
  t.is(user.last_name, "NovoSobrenome");
133 -
  t.is(user.timezone, "Europe/London");
134 -
});
135 -

136 -
test.serial("Falha ao atualizar com email inválido", async (t) => {
137 -
  const res = await request(app)
138 -
    .put(`/users/${userId}`)
139 -
    .send({
140 -
      email: "emailinvalido"
141 -
    });
142 -

143 -
  t.is(res.status, 400);
144 -
  t.is(res.body.error, "Email inválido");
145 -
});
146 -

147 -
test.serial("Falha ao atualizar com senha muito curta", async (t) => {
148 -
  const res = await request(app)
149 -
    .put(`/users/${userId}`)
150 -
    .send({
151 -
      password: "123"
152 -
    });
153 -

154 -
  t.is(res.status, 400);
155 -
  t.is(res.body.error, "Senha deve ter pelo menos 6 caracteres");
156 -
});
157 -

158 -
test.serial("Falha ao atualizar email para um já existente", async (t) => {
159 -
  // Create another user
160 -
  await request(app)
161 -
    .post("/users")
162 -
    .send({
163 -
      email: "outro@example.com",
164 -
      password: "senha123",
165 -
      first_name: "Outro",
166 -
      last_name: "Usuario"
167 -
    });
168 -

169 -
  // Try to update to existing email
170 -
  const res = await request(app)
171 -
    .put(`/users/${userId}`)
172 -
    .send({
173 -
      email: "outro@example.com"
174 -
    });
175 -

176 -
  t.is(res.status, 400);
177 -
  t.is(res.body.error, "Email já está em uso");
178 -
});
179 -

180 -
test.serial("Falha ao atualizar usuário inexistente", async (t) => {
181 -
  const res = await request(app)
182 -
    .put("/users/99999")
183 -
    .send({
184 -
      first_name: "Novo"
185 -
    });
186 -

187 -
  t.is(res.status, 404);
188 -
  t.is(res.body.error, "Usuário não encontrado");
189 -
});
190 -

191 -
test.serial("Falha ao atualizar sem campos", async (t) => {
192 -
  const res = await request(app)
193 -
    .put(`/users/${userId}`)
194 -
    .send({});
195 -

196 -
  t.is(res.status, 400);
197 -
  t.is(res.body.error, "Nenhum campo para atualizar");
198 -
});
199 -

200 -
test.serial("Deletar usuário existente", async (t) => {
201 -
  const res = await request(app).delete(`/users/${userId}`);
202 -

203 -
  t.is(res.status, 200);
204 -
  t.true(res.body.success);
205 -
  t.is(Number(res.body.deleted), Number(userId));
206 -

207 -
  // Verify user is deleted
208 -
  const user = db.prepare("SELECT * FROM users WHERE id = ?").get(userId);
209 -
  t.falsy(user);
210 -
});
211 -

212 -
test.serial("Deletar usuário deve deletar seus registros de humores (em cascata)", async (t) => {
213 -
  // Add a mood
214 -
  const now = new Date().toISOString();
215 -
  const moodResult = db.prepare(`
216 -
    INSERT INTO mood (user_id, rating, stress_level, anxiety_level, energy_level, recorded_at)
217 -
    VALUES (?, ?, ?, ?, ?, ?)
218 -
  `).run(userId, 7, 3, 4, 8, now);
219 -

220 -
  const moodId = moodResult.lastInsertRowid;
221 -

222 -
  // Add mood components
223 -
  db.prepare(`
224 -
    INSERT INTO mood_components (mood_id, emotion, intensity)
225 -
    VALUES (?, ?, ?)
226 -
  `).run(moodId, 'joy', 8);
227 -

228 -
  // Delete user
229 -
  const res = await request(app).delete(`/users/${userId}`);
230 -
  t.is(res.status, 200);
231 -

232 -
  // Verify moods are deleted
233 -
  const mood = db.prepare("SELECT * FROM mood WHERE user_id = ?").get(userId);
234 -
  t.falsy(mood);
235 -

236 -
  // Verify mood components are deleted
237 -
  const component = db.prepare("SELECT * FROM mood_components WHERE mood_id = ?").get(moodId);
238 -
  t.falsy(component);
239 -
});
240 -

241 -
test.serial("Falha ao deletar usuário inexistente", async (t) => {
242 -
  const res = await request(app).delete("/users/99999");
243 -

244 -
  t.is(res.status, 404);
245 -
  t.is(res.body.error, "Usuário não encontrado");
246 -
});