achievements-engine 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1675,6 +1675,276 @@ class OfflineQueueStorage {
1675
1675
  }
1676
1676
  }
1677
1677
 
1678
+ /**
1679
+ * Base class for chainable achievement configuration (Tier 2)
1680
+ */
1681
+ class Achievement {
1682
+ constructor(metric, defaultAward) {
1683
+ this.metric = metric;
1684
+ this.award = defaultAward;
1685
+ }
1686
+ /**
1687
+ * Customize the award details for this achievement
1688
+ * @param award - Custom award details
1689
+ * @returns This achievement for chaining
1690
+ */
1691
+ withAward(award) {
1692
+ this.award = Object.assign(Object.assign({}, this.award), award);
1693
+ return this;
1694
+ }
1695
+ }
1696
+ /**
1697
+ * Threshold-based achievement (score, level, etc.)
1698
+ */
1699
+ class ThresholdAchievement extends Achievement {
1700
+ constructor(metric, threshold, defaultAward) {
1701
+ super(metric, defaultAward);
1702
+ this.threshold = threshold;
1703
+ }
1704
+ toConfig() {
1705
+ return {
1706
+ [this.metric]: {
1707
+ [this.threshold]: {
1708
+ title: this.award.title,
1709
+ description: this.award.description,
1710
+ icon: this.award.icon
1711
+ }
1712
+ }
1713
+ };
1714
+ }
1715
+ }
1716
+ /**
1717
+ * Boolean achievement (tutorial completion, first login, etc.)
1718
+ */
1719
+ class BooleanAchievement extends Achievement {
1720
+ toConfig() {
1721
+ return {
1722
+ [this.metric]: {
1723
+ true: {
1724
+ title: this.award.title,
1725
+ description: this.award.description,
1726
+ icon: this.award.icon
1727
+ }
1728
+ }
1729
+ };
1730
+ }
1731
+ }
1732
+ /**
1733
+ * Value-based achievement (character class, difficulty, etc.)
1734
+ */
1735
+ class ValueAchievement extends Achievement {
1736
+ constructor(metric, value, defaultAward) {
1737
+ super(metric, defaultAward);
1738
+ this.value = value;
1739
+ }
1740
+ toConfig() {
1741
+ return {
1742
+ [this.metric]: {
1743
+ [this.value]: {
1744
+ title: this.award.title,
1745
+ description: this.award.description,
1746
+ icon: this.award.icon
1747
+ }
1748
+ }
1749
+ };
1750
+ }
1751
+ }
1752
+ /**
1753
+ * Complex achievement builder for power users (Tier 3)
1754
+ */
1755
+ class ComplexAchievementBuilder {
1756
+ constructor() {
1757
+ this.metric = '';
1758
+ this.condition = null;
1759
+ this.award = {};
1760
+ }
1761
+ /**
1762
+ * Set the metric this achievement tracks
1763
+ */
1764
+ withMetric(metric) {
1765
+ this.metric = metric;
1766
+ return this;
1767
+ }
1768
+ /**
1769
+ * Set the condition function that determines if achievement is unlocked
1770
+ */
1771
+ withCondition(fn) {
1772
+ this.condition = fn;
1773
+ return this;
1774
+ }
1775
+ /**
1776
+ * Set the award details for this achievement
1777
+ */
1778
+ withAward(award) {
1779
+ this.award = Object.assign(Object.assign({}, this.award), award);
1780
+ return this;
1781
+ }
1782
+ /**
1783
+ * Build the final achievement configuration
1784
+ */
1785
+ build() {
1786
+ if (!this.metric || !this.condition) {
1787
+ throw new Error('Complex achievement requires metric and condition');
1788
+ }
1789
+ return {
1790
+ [this.metric]: {
1791
+ custom: {
1792
+ title: this.award.title || this.metric,
1793
+ description: this.award.description || `Achieve ${this.award.title || this.metric}`,
1794
+ icon: this.award.icon || '💎',
1795
+ condition: this.condition
1796
+ }
1797
+ }
1798
+ };
1799
+ }
1800
+ }
1801
+ /**
1802
+ * Main AchievementBuilder with three-tier API
1803
+ * Tier 1: Simple static methods with smart defaults
1804
+ * Tier 2: Chainable customization
1805
+ * Tier 3: Full builder for complex logic
1806
+ */
1807
+ class AchievementBuilder {
1808
+ // TIER 1: Simple Static Methods (90% of use cases)
1809
+ /**
1810
+ * Create a single score achievement with smart defaults
1811
+ * @param threshold - Score threshold to achieve
1812
+ * @returns Chainable ThresholdAchievement
1813
+ */
1814
+ static createScoreAchievement(threshold) {
1815
+ return new ThresholdAchievement('score', threshold, {
1816
+ title: `Score ${threshold}!`,
1817
+ description: `Score ${threshold} points`,
1818
+ icon: '🏆'
1819
+ });
1820
+ }
1821
+ /**
1822
+ * Create multiple score achievements
1823
+ * @param thresholds - Array of thresholds or [threshold, award] tuples
1824
+ * @returns Complete SimpleAchievementConfig
1825
+ */
1826
+ static createScoreAchievements(thresholds) {
1827
+ const config = { score: {} };
1828
+ thresholds.forEach(item => {
1829
+ if (typeof item === 'number') {
1830
+ // Use default award
1831
+ config.score[item] = {
1832
+ title: `Score ${item}!`,
1833
+ description: `Score ${item} points`,
1834
+ icon: '🏆'
1835
+ };
1836
+ }
1837
+ else {
1838
+ // Custom award
1839
+ const [threshold, award] = item;
1840
+ config.score[threshold] = {
1841
+ title: award.title || `Score ${threshold}!`,
1842
+ description: award.description || `Score ${threshold} points`,
1843
+ icon: award.icon || '🏆'
1844
+ };
1845
+ }
1846
+ });
1847
+ return config;
1848
+ }
1849
+ /**
1850
+ * Create a single level achievement with smart defaults
1851
+ * @param level - Level threshold to achieve
1852
+ * @returns Chainable ThresholdAchievement
1853
+ */
1854
+ static createLevelAchievement(level) {
1855
+ return new ThresholdAchievement('level', level, {
1856
+ title: `Level ${level}!`,
1857
+ description: `Reach level ${level}`,
1858
+ icon: '📈'
1859
+ });
1860
+ }
1861
+ /**
1862
+ * Create multiple level achievements
1863
+ * @param levels - Array of levels or [level, award] tuples
1864
+ * @returns Complete SimpleAchievementConfig
1865
+ */
1866
+ static createLevelAchievements(levels) {
1867
+ const config = { level: {} };
1868
+ levels.forEach(item => {
1869
+ if (typeof item === 'number') {
1870
+ // Use default award
1871
+ config.level[item] = {
1872
+ title: `Level ${item}!`,
1873
+ description: `Reach level ${item}`,
1874
+ icon: '📈'
1875
+ };
1876
+ }
1877
+ else {
1878
+ // Custom award
1879
+ const [level, award] = item;
1880
+ config.level[level] = {
1881
+ title: award.title || `Level ${level}!`,
1882
+ description: award.description || `Reach level ${level}`,
1883
+ icon: award.icon || '📈'
1884
+ };
1885
+ }
1886
+ });
1887
+ return config;
1888
+ }
1889
+ /**
1890
+ * Create a boolean achievement with smart defaults
1891
+ * @param metric - The metric name (e.g., 'completedTutorial')
1892
+ * @returns Chainable BooleanAchievement
1893
+ */
1894
+ static createBooleanAchievement(metric) {
1895
+ // Convert camelCase to Title Case
1896
+ const formattedMetric = metric.replace(/([A-Z])/g, ' $1').toLowerCase();
1897
+ const titleCase = formattedMetric.charAt(0).toUpperCase() + formattedMetric.slice(1);
1898
+ return new BooleanAchievement(metric, {
1899
+ title: `${titleCase}!`,
1900
+ description: `Complete ${formattedMetric}`,
1901
+ icon: '✅'
1902
+ });
1903
+ }
1904
+ /**
1905
+ * Create a value-based achievement with smart defaults
1906
+ * @param metric - The metric name (e.g., 'characterClass')
1907
+ * @param value - The value to match (e.g., 'wizard')
1908
+ * @returns Chainable ValueAchievement
1909
+ */
1910
+ static createValueAchievement(metric, value) {
1911
+ const formattedValue = value.charAt(0).toUpperCase() + value.slice(1);
1912
+ return new ValueAchievement(metric, value, {
1913
+ title: `${formattedValue}!`,
1914
+ description: `Choose ${formattedValue.toLowerCase()} for ${metric}`,
1915
+ icon: '🎯'
1916
+ });
1917
+ }
1918
+ // TIER 3: Full Builder for Complex Logic
1919
+ /**
1920
+ * Create a complex achievement builder for power users
1921
+ * @returns ComplexAchievementBuilder for full control
1922
+ */
1923
+ static create() {
1924
+ return new ComplexAchievementBuilder();
1925
+ }
1926
+ // UTILITY METHODS
1927
+ /**
1928
+ * Combine multiple achievement configurations
1929
+ * @param achievements - Array of SimpleAchievementConfig objects or Achievement instances
1930
+ * @returns Combined SimpleAchievementConfig
1931
+ */
1932
+ static combine(achievements) {
1933
+ const combined = {};
1934
+ achievements.forEach(achievement => {
1935
+ const config = achievement instanceof Achievement ? achievement.toConfig() : achievement;
1936
+ Object.keys(config).forEach(key => {
1937
+ if (!combined[key]) {
1938
+ combined[key] = {};
1939
+ }
1940
+ Object.assign(combined[key], config[key]);
1941
+ });
1942
+ });
1943
+ return combined;
1944
+ }
1945
+ }
1946
+
1947
+ exports.AchievementBuilder = AchievementBuilder;
1678
1948
  exports.AchievementEngine = AchievementEngine;
1679
1949
  exports.AchievementError = AchievementError;
1680
1950
  exports.AsyncStorageAdapter = AsyncStorageAdapter;
@@ -1695,5 +1965,6 @@ exports.importAchievementData = importAchievementData;
1695
1965
  exports.isAchievementError = isAchievementError;
1696
1966
  exports.isAsyncStorage = isAsyncStorage;
1697
1967
  exports.isRecoverableError = isRecoverableError;
1968
+ exports.isSimpleConfig = isSimpleConfig;
1698
1969
  exports.normalizeAchievements = normalizeAchievements;
1699
1970
  //# sourceMappingURL=index.cjs.map