@pixels-online/pixels-client-js-sdk 1.16.0 → 1.18.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.esm.js +307 -54
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +309 -53
- package/dist/index.js.map +1 -1
- package/dist/offerwall-sdk.umd.js +309 -53
- package/dist/offerwall-sdk.umd.js.map +1 -1
- package/dist/types/blockchain/user_wallet.d.ts +1 -2
- package/dist/types/offer.d.ts +22 -10
- package/dist/types/player.d.ts +13 -7
- package/dist/utils/conditions.d.ts +49 -8
- package/dist/utils/template.d.ts +18 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1278,19 +1278,47 @@ class OfferwallClient {
|
|
|
1278
1278
|
}
|
|
1279
1279
|
|
|
1280
1280
|
const keyPattern = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
1281
|
-
|
|
1281
|
+
/**
|
|
1282
|
+
* This replaces {keyName} keys from the template with corresponding values from the dynamic object.
|
|
1283
|
+
*/
|
|
1282
1284
|
function renderTemplate(template, dynamic) {
|
|
1283
1285
|
if (!template)
|
|
1284
1286
|
return '';
|
|
1285
|
-
return template.replace(keyPattern, (
|
|
1287
|
+
return template.replace(keyPattern, (_match, key) => {
|
|
1288
|
+
if (dynamic && typeof dynamic[key] === 'boolean') {
|
|
1289
|
+
return dynamic[key] ? '✓' : '✗';
|
|
1290
|
+
}
|
|
1286
1291
|
if (dynamic && dynamic[key] !== undefined) {
|
|
1287
1292
|
return String(dynamic[key]);
|
|
1288
1293
|
}
|
|
1289
1294
|
return '{?}'; // indicate missing key
|
|
1290
1295
|
});
|
|
1291
1296
|
}
|
|
1297
|
+
/**
|
|
1298
|
+
* This replaces {{keyName}} in dynamic condition keys with corresponding values from
|
|
1299
|
+
* the PlayerOffer.trackers
|
|
1300
|
+
*
|
|
1301
|
+
* eg. a condition high_score_pet-{{surfacerPlayerId}} with high_score_pet-12345
|
|
1302
|
+
*/
|
|
1303
|
+
function replaceDynamicConditionKey(key, trackers) {
|
|
1304
|
+
return key?.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (match, p1) => {
|
|
1305
|
+
const value = trackers[p1];
|
|
1306
|
+
return value !== undefined ? String(value) : match;
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
/** this replaces all of the dynamic conditions.keys by calling replaceDynamicConditionKey */
|
|
1310
|
+
function replaceDynamicConditionKeys(conditions, trackers) {
|
|
1311
|
+
return conditions.map((condition) => ({
|
|
1312
|
+
...condition,
|
|
1313
|
+
key: replaceDynamicConditionKey(condition.key, trackers),
|
|
1314
|
+
}));
|
|
1315
|
+
}
|
|
1292
1316
|
|
|
1293
|
-
const meetsBaseConditions = ({ conditions, playerSnap, addDetails,
|
|
1317
|
+
const meetsBaseConditions = ({ conditions, playerSnap, addDetails,
|
|
1318
|
+
/** this exists if calling meetsBaseConditions from meetsCompletionConditions. but surfacing
|
|
1319
|
+
* check doesn't use this since we don't have a playerOffer at surfacing time
|
|
1320
|
+
*/
|
|
1321
|
+
playerOffer, }) => {
|
|
1294
1322
|
const conditionData = [];
|
|
1295
1323
|
let isValid = true;
|
|
1296
1324
|
if (conditions?.minDaysInGame) {
|
|
@@ -1657,7 +1685,11 @@ const meetsBaseConditions = ({ conditions, playerSnap, addDetails, }) => {
|
|
|
1657
1685
|
}
|
|
1658
1686
|
// Evaluate dynamic conditions
|
|
1659
1687
|
if (conditions?.dynamic?.conditions?.length) {
|
|
1660
|
-
const
|
|
1688
|
+
const resolvedConditions = replaceDynamicConditionKeys(conditions.dynamic.conditions, playerOffer?.trackers || {});
|
|
1689
|
+
const dynamicResult = meetsDynamicConditions(playerSnap.dynamic, {
|
|
1690
|
+
...conditions.dynamic,
|
|
1691
|
+
conditions: resolvedConditions,
|
|
1692
|
+
});
|
|
1661
1693
|
if (addDetails) {
|
|
1662
1694
|
conditionData.push({
|
|
1663
1695
|
isMet: dynamicResult,
|
|
@@ -1766,6 +1798,31 @@ const meetsSurfacingConditions = ({ surfacingConditions, playerSnap, context, pl
|
|
|
1766
1798
|
return { isValid: false };
|
|
1767
1799
|
}
|
|
1768
1800
|
}
|
|
1801
|
+
if (conditions.allowedCountries?.length) {
|
|
1802
|
+
const playerCountry = playerSnap.ip?.countryCode;
|
|
1803
|
+
if (!playerCountry || !conditions.allowedCountries.includes(playerCountry)) {
|
|
1804
|
+
return { isValid: false };
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
if (conditions.restrictedCountries?.length) {
|
|
1808
|
+
const playerCountry = playerSnap.ip?.countryCode;
|
|
1809
|
+
if (!playerCountry) {
|
|
1810
|
+
return { isValid: false };
|
|
1811
|
+
}
|
|
1812
|
+
if (conditions.restrictedCountries.includes(playerCountry)) {
|
|
1813
|
+
return { isValid: false };
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
if (conditions.networkRestrictions?.length) {
|
|
1817
|
+
if (!playerSnap.ip) {
|
|
1818
|
+
return { isValid: false };
|
|
1819
|
+
}
|
|
1820
|
+
for (const restriction of conditions.networkRestrictions) {
|
|
1821
|
+
if (playerSnap.ip[restriction]) {
|
|
1822
|
+
return { isValid: false };
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1769
1826
|
return meetsBaseConditions({ conditions, playerSnap });
|
|
1770
1827
|
};
|
|
1771
1828
|
const hasConditions = (conditions) => {
|
|
@@ -1818,6 +1875,12 @@ const hasConditions = (conditions) => {
|
|
|
1818
1875
|
return true;
|
|
1819
1876
|
if (surCond.links && Object.keys(surCond.links).length > 0)
|
|
1820
1877
|
return true;
|
|
1878
|
+
if (surCond.allowedCountries?.length)
|
|
1879
|
+
return true;
|
|
1880
|
+
if (surCond.restrictedCountries?.length)
|
|
1881
|
+
return true;
|
|
1882
|
+
if (surCond.networkRestrictions?.length)
|
|
1883
|
+
return true;
|
|
1821
1884
|
const compCond = conditions;
|
|
1822
1885
|
if (compCond.context)
|
|
1823
1886
|
return true;
|
|
@@ -1839,11 +1902,25 @@ const hasConditions = (conditions) => {
|
|
|
1839
1902
|
return true;
|
|
1840
1903
|
return false;
|
|
1841
1904
|
};
|
|
1842
|
-
const
|
|
1905
|
+
const offerMeetsCompletionConditions = (offer, snapshot) => {
|
|
1906
|
+
return meetsCompletionConditions({
|
|
1907
|
+
completionConditions: offer.completionConditions || {},
|
|
1908
|
+
completionTrackers: offer.completionTrackers,
|
|
1909
|
+
playerSnap: snapshot,
|
|
1910
|
+
playerOffer: offer,
|
|
1911
|
+
addDetails: true,
|
|
1912
|
+
});
|
|
1913
|
+
};
|
|
1914
|
+
const meetsCompletionConditions = ({ completionConditions, completionTrackers, playerSnap, playerOffer, addDetails = false, maxClaimCount, }) => {
|
|
1843
1915
|
if (completionConditions) {
|
|
1844
1916
|
const conditions = completionConditions;
|
|
1917
|
+
// For multi-claim offers, scale cumulative requirements by (claimedCount + 1)
|
|
1918
|
+
const shouldScale = maxClaimCount === -1 || (maxClaimCount && maxClaimCount > 1);
|
|
1919
|
+
const claimMultiplier = shouldScale ? (playerOffer.claimedCount || 0) + 1 : 1;
|
|
1845
1920
|
const conditionData = [];
|
|
1846
1921
|
let isValid = true;
|
|
1922
|
+
let maxTotalClaimsFromScaling = Infinity;
|
|
1923
|
+
const updateMax = (limit) => (maxTotalClaimsFromScaling = Math.min(maxTotalClaimsFromScaling, limit));
|
|
1847
1924
|
if (completionConditions?.context?.id) {
|
|
1848
1925
|
const hasTrackedContext = completionTrackers?.context &&
|
|
1849
1926
|
completionConditions.context.id === completionTrackers.context;
|
|
@@ -1860,73 +1937,93 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
1860
1937
|
}
|
|
1861
1938
|
else {
|
|
1862
1939
|
if (isDisqualify)
|
|
1863
|
-
return { isValid: false };
|
|
1940
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1864
1941
|
}
|
|
1865
1942
|
}
|
|
1866
1943
|
if (conditions?.buyItem) {
|
|
1867
|
-
const
|
|
1944
|
+
const baseAmount = conditions.buyItem.amount || 1;
|
|
1945
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
1946
|
+
const trackerValue = completionTrackers?.buyItem || 0;
|
|
1947
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
1948
|
+
if (shouldScale && baseAmount > 0) {
|
|
1949
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
1950
|
+
}
|
|
1868
1951
|
if (addDetails) {
|
|
1869
1952
|
conditionData.push({
|
|
1870
1953
|
isMet: !isDisqualify,
|
|
1871
1954
|
kind: 'buyItem',
|
|
1872
|
-
trackerAmount:
|
|
1873
|
-
text: `Buy ${
|
|
1955
|
+
trackerAmount: trackerValue,
|
|
1956
|
+
text: `Buy ${scaledAmount} ${conditions.buyItem.name}`,
|
|
1874
1957
|
});
|
|
1875
1958
|
if (isDisqualify)
|
|
1876
1959
|
isValid = false;
|
|
1877
1960
|
}
|
|
1878
1961
|
else {
|
|
1879
1962
|
if (isDisqualify)
|
|
1880
|
-
return { isValid: false };
|
|
1963
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1881
1964
|
}
|
|
1882
1965
|
}
|
|
1883
1966
|
if (conditions?.spendCurrency) {
|
|
1884
|
-
const
|
|
1967
|
+
const baseAmount = conditions.spendCurrency.amount || 1;
|
|
1968
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
1969
|
+
const trackerValue = completionTrackers?.spendCurrency || 0;
|
|
1970
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
1971
|
+
if (shouldScale && baseAmount > 0) {
|
|
1972
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
1973
|
+
}
|
|
1885
1974
|
if (addDetails) {
|
|
1886
1975
|
conditionData.push({
|
|
1887
1976
|
isMet: !isDisqualify,
|
|
1888
1977
|
kind: 'spendCurrency',
|
|
1889
|
-
trackerAmount:
|
|
1890
|
-
text: `Spend ${
|
|
1978
|
+
trackerAmount: trackerValue,
|
|
1979
|
+
text: `Spend ${scaledAmount} ${conditions.spendCurrency.name}`,
|
|
1891
1980
|
});
|
|
1892
1981
|
if (isDisqualify)
|
|
1893
1982
|
isValid = false;
|
|
1894
1983
|
}
|
|
1895
1984
|
else {
|
|
1896
1985
|
if (isDisqualify)
|
|
1897
|
-
return { isValid: false };
|
|
1986
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1898
1987
|
}
|
|
1899
1988
|
}
|
|
1900
1989
|
if (conditions?.depositCurrency) {
|
|
1901
|
-
const
|
|
1902
|
-
|
|
1990
|
+
const baseAmount = conditions.depositCurrency.amount || 1;
|
|
1991
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
1992
|
+
const trackerValue = completionTrackers?.depositCurrency || 0;
|
|
1993
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
1994
|
+
if (shouldScale && baseAmount > 0) {
|
|
1995
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
1996
|
+
}
|
|
1903
1997
|
if (addDetails) {
|
|
1904
1998
|
conditionData.push({
|
|
1905
1999
|
isMet: !isDisqualify,
|
|
1906
2000
|
kind: 'depositCurrency',
|
|
1907
|
-
trackerAmount:
|
|
1908
|
-
text: `Deposit ${
|
|
2001
|
+
trackerAmount: trackerValue,
|
|
2002
|
+
text: `Deposit ${scaledAmount} ${conditions.depositCurrency.name}`,
|
|
1909
2003
|
});
|
|
2004
|
+
if (isDisqualify)
|
|
2005
|
+
isValid = false;
|
|
1910
2006
|
}
|
|
1911
2007
|
else {
|
|
1912
2008
|
if (isDisqualify)
|
|
1913
|
-
return { isValid: false };
|
|
2009
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1914
2010
|
}
|
|
1915
2011
|
}
|
|
1916
2012
|
if (conditions?.login) {
|
|
1917
|
-
const isMet =
|
|
2013
|
+
const isMet = new Date(playerSnap.snapshotLastUpdated || 0).getTime() >
|
|
2014
|
+
new Date(playerOffer.createdAt || 0).getTime();
|
|
1918
2015
|
if (addDetails) {
|
|
1919
2016
|
conditionData.push({
|
|
1920
2017
|
isMet,
|
|
1921
2018
|
kind: 'login',
|
|
1922
|
-
trackerAmount:
|
|
2019
|
+
trackerAmount: isMet ? 1 : 0,
|
|
1923
2020
|
text: `Login to the game`,
|
|
1924
2021
|
});
|
|
1925
2022
|
isValid = isMet;
|
|
1926
2023
|
}
|
|
1927
2024
|
else {
|
|
1928
2025
|
if (!isMet)
|
|
1929
|
-
return { isValid: false };
|
|
2026
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1930
2027
|
}
|
|
1931
2028
|
}
|
|
1932
2029
|
if (conditions?.loginStreak) {
|
|
@@ -1946,7 +2043,7 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
1946
2043
|
}
|
|
1947
2044
|
else {
|
|
1948
2045
|
if (isDisqualify)
|
|
1949
|
-
return { isValid: false };
|
|
2046
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1950
2047
|
}
|
|
1951
2048
|
}
|
|
1952
2049
|
if (conditions?.social) {
|
|
@@ -1956,9 +2053,11 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
1956
2053
|
const hasContent = Boolean(mode === 'accumulate'
|
|
1957
2054
|
? tSocial?.mode === 'accumulate'
|
|
1958
2055
|
: tSocial && tSocial.mode !== 'accumulate' && !!tSocial.videoId);
|
|
1959
|
-
|
|
1960
|
-
const
|
|
1961
|
-
const
|
|
2056
|
+
// Only scale social metrics in accumulate mode (attach mode is single content)
|
|
2057
|
+
const socialMultiplier = mode === 'accumulate' ? claimMultiplier : 1;
|
|
2058
|
+
const minLikes = (cSocial?.minLikes || 0) * socialMultiplier;
|
|
2059
|
+
const minViews = (cSocial?.minViews || 0) * socialMultiplier;
|
|
2060
|
+
const minComments = (cSocial?.minComments || 0) * socialMultiplier;
|
|
1962
2061
|
const likes = tSocial?.likes || 0;
|
|
1963
2062
|
const views = tSocial?.views || 0;
|
|
1964
2063
|
const comments = tSocial?.comments || 0;
|
|
@@ -1966,6 +2065,17 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
1966
2065
|
if (likes < minLikes || views < minViews || comments < minComments) {
|
|
1967
2066
|
isDisqualify = true;
|
|
1968
2067
|
}
|
|
2068
|
+
if (shouldScale && mode === 'accumulate' && hasContent) {
|
|
2069
|
+
const baseLikes = cSocial?.minLikes || 0;
|
|
2070
|
+
const baseViews = cSocial?.minViews || 0;
|
|
2071
|
+
const baseComments = cSocial?.minComments || 0;
|
|
2072
|
+
if (baseLikes > 0)
|
|
2073
|
+
updateMax(Math.floor(likes / baseLikes));
|
|
2074
|
+
if (baseViews > 0)
|
|
2075
|
+
updateMax(Math.floor(views / baseViews));
|
|
2076
|
+
if (baseComments > 0)
|
|
2077
|
+
updateMax(Math.floor(comments / baseComments));
|
|
2078
|
+
}
|
|
1969
2079
|
if (addDetails) {
|
|
1970
2080
|
const platformMap = {
|
|
1971
2081
|
tiktok: 'TikTok',
|
|
@@ -2037,31 +2147,47 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2037
2147
|
}
|
|
2038
2148
|
else {
|
|
2039
2149
|
if (isDisqualify)
|
|
2040
|
-
return { isValid: false };
|
|
2150
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2041
2151
|
}
|
|
2042
2152
|
}
|
|
2043
2153
|
// Linked completions - wait for N linked entities to complete
|
|
2044
2154
|
if (conditions?.linkedCompletions?.min) {
|
|
2155
|
+
const baseMin = conditions.linkedCompletions.min;
|
|
2045
2156
|
const currentCount = completionTrackers?.linkedCompletions || 0;
|
|
2046
|
-
const
|
|
2047
|
-
const isDisqualify = currentCount <
|
|
2157
|
+
const scaledMin = baseMin * claimMultiplier;
|
|
2158
|
+
const isDisqualify = currentCount < scaledMin;
|
|
2159
|
+
if (shouldScale && baseMin > 0) {
|
|
2160
|
+
updateMax(Math.floor(currentCount / baseMin));
|
|
2161
|
+
}
|
|
2048
2162
|
if (addDetails) {
|
|
2049
2163
|
conditionData.push({
|
|
2050
2164
|
isMet: !isDisqualify,
|
|
2051
2165
|
kind: 'linkedCompletions',
|
|
2052
2166
|
trackerAmount: currentCount,
|
|
2053
|
-
text: `Wait for ${
|
|
2167
|
+
text: `Wait for ${scaledMin} linked ${scaledMin === 1 ? 'entity' : 'entities'} to complete`,
|
|
2054
2168
|
});
|
|
2055
2169
|
if (isDisqualify)
|
|
2056
2170
|
isValid = false;
|
|
2057
2171
|
}
|
|
2058
2172
|
else {
|
|
2059
2173
|
if (isDisqualify)
|
|
2060
|
-
return { isValid: false };
|
|
2174
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2061
2175
|
}
|
|
2062
2176
|
}
|
|
2063
2177
|
if (conditions?.dynamicTracker?.conditions?.length) {
|
|
2064
|
-
const
|
|
2178
|
+
const resolvedConditions = replaceDynamicConditionKeys(conditions.dynamicTracker.conditions, playerOffer?.trackers || {});
|
|
2179
|
+
// now we have the game-defined conditions with {{}} keys populated. feed these conditions into evaluator
|
|
2180
|
+
const dynamicResult = meetsDynamicConditions(completionTrackers?.dynamicTracker, {
|
|
2181
|
+
...conditions.dynamicTracker,
|
|
2182
|
+
conditions: resolvedConditions,
|
|
2183
|
+
}, claimMultiplier);
|
|
2184
|
+
if (shouldScale) {
|
|
2185
|
+
const dynamicMax = getMaxClaimsForDynamicGroup(completionTrackers?.dynamicTracker || {}, {
|
|
2186
|
+
...conditions.dynamicTracker,
|
|
2187
|
+
conditions: resolvedConditions,
|
|
2188
|
+
}, playerOffer.claimedCount || 0);
|
|
2189
|
+
updateMax(dynamicMax);
|
|
2190
|
+
}
|
|
2065
2191
|
if (addDetails) {
|
|
2066
2192
|
conditionData.push({
|
|
2067
2193
|
isMet: dynamicResult,
|
|
@@ -2073,19 +2199,29 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2073
2199
|
}
|
|
2074
2200
|
else {
|
|
2075
2201
|
if (!dynamicResult)
|
|
2076
|
-
return { isValid: false };
|
|
2202
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2077
2203
|
}
|
|
2078
2204
|
}
|
|
2079
2205
|
const r = meetsBaseConditions({
|
|
2080
2206
|
conditions,
|
|
2081
2207
|
playerSnap,
|
|
2082
2208
|
addDetails: true,
|
|
2209
|
+
playerOffer,
|
|
2083
2210
|
});
|
|
2084
2211
|
isValid = isValid && r.isValid;
|
|
2085
2212
|
conditionData.push(...(r.conditionData || []));
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2213
|
+
if (maxClaimCount && maxClaimCount > 0) {
|
|
2214
|
+
updateMax(maxClaimCount);
|
|
2215
|
+
}
|
|
2216
|
+
const claimedCount = playerOffer.claimedCount || 0;
|
|
2217
|
+
let availableClaimsNow = !isValid
|
|
2218
|
+
? 0
|
|
2219
|
+
: maxTotalClaimsFromScaling === Infinity
|
|
2220
|
+
? -1
|
|
2221
|
+
: Math.max(0, maxTotalClaimsFromScaling - claimedCount);
|
|
2222
|
+
return { isValid, conditionData, availableClaimsNow };
|
|
2223
|
+
}
|
|
2224
|
+
return { isValid: true, conditionData: [], availableClaimsNow: -1 };
|
|
2089
2225
|
};
|
|
2090
2226
|
/**
|
|
2091
2227
|
* Checks if completion conditions were met before a specific expiry time.
|
|
@@ -2094,10 +2230,9 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2094
2230
|
* @param completionConditions - The completion conditions to check
|
|
2095
2231
|
* @param completionTrackers - The completion trackers (for buyItem, spendCurrency, etc.)
|
|
2096
2232
|
* @param playerSnap - The player snapshot with field timestamps
|
|
2097
|
-
* @param expiryTime - The expiry timestamp in milliseconds
|
|
2098
2233
|
* @returns true if all conditions were met before expiry, false otherwise
|
|
2099
2234
|
*/
|
|
2100
|
-
const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completionTrackers, playerSnap,
|
|
2235
|
+
const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completionTrackers, playerSnap, playerOffer, maxClaimCount, }) => {
|
|
2101
2236
|
if (!completionConditions)
|
|
2102
2237
|
return false;
|
|
2103
2238
|
// Check if there are actually any conditions to evaluate
|
|
@@ -2107,10 +2242,15 @@ const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completio
|
|
|
2107
2242
|
const conditionsMet = meetsCompletionConditions({
|
|
2108
2243
|
completionConditions,
|
|
2109
2244
|
completionTrackers,
|
|
2245
|
+
playerOffer,
|
|
2110
2246
|
playerSnap,
|
|
2247
|
+
maxClaimCount,
|
|
2111
2248
|
});
|
|
2112
2249
|
if (!conditionsMet.isValid)
|
|
2113
2250
|
return false;
|
|
2251
|
+
if (!playerOffer.expiresAt)
|
|
2252
|
+
return true;
|
|
2253
|
+
const expiryTime = new Date(playerOffer.expiresAt).getTime();
|
|
2114
2254
|
const lastSnapshotUpdate = new Date(playerSnap.snapshotLastUpdated).getTime();
|
|
2115
2255
|
/**
|
|
2116
2256
|
* Checks if a field was updated after the expiry time.
|
|
@@ -2221,37 +2361,55 @@ const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completio
|
|
|
2221
2361
|
* Checks if a dynamic object meets a set of dynamic field conditions.
|
|
2222
2362
|
* @param dynamicObj - The object with any key and string or number value.
|
|
2223
2363
|
* @param conditions - Array of conditions to check.
|
|
2364
|
+
* @param claimMultiplier - Multiplier to scale conditions (used for numeric comparisons).
|
|
2224
2365
|
* @returns true if all conditions are met, false otherwise.
|
|
2225
2366
|
*/
|
|
2226
2367
|
/**
|
|
2227
2368
|
* Evaluates a single dynamic condition against the dynamic object.
|
|
2228
2369
|
*/
|
|
2229
|
-
function evaluateDynamicCondition(dynamicObj, cond) {
|
|
2370
|
+
function evaluateDynamicCondition(dynamicObj, cond, claimMultiplier = 1) {
|
|
2371
|
+
if (!dynamicObj)
|
|
2372
|
+
return false;
|
|
2230
2373
|
const val = dynamicObj[cond.key];
|
|
2231
2374
|
if (val === undefined)
|
|
2232
2375
|
return false;
|
|
2233
2376
|
const isNumber = typeof val === 'number';
|
|
2234
|
-
const
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2377
|
+
const isBoolean = typeof val === 'boolean';
|
|
2378
|
+
if (isBoolean) {
|
|
2379
|
+
switch (cond.operator) {
|
|
2380
|
+
case '==':
|
|
2381
|
+
return val === Boolean(cond.compareTo);
|
|
2382
|
+
case '!=':
|
|
2383
|
+
return val !== Boolean(cond.compareTo);
|
|
2384
|
+
default:
|
|
2385
|
+
return false;
|
|
2386
|
+
}
|
|
2240
2387
|
}
|
|
2388
|
+
const compareTo = isNumber ? Number(cond.compareTo) : String(cond.compareTo);
|
|
2241
2389
|
if (isNumber && typeof compareTo === 'number') {
|
|
2390
|
+
const skipMultiplier = cond.operator === '==' || cond.operator === '!=';
|
|
2391
|
+
const scaledCompareTo = skipMultiplier ? compareTo : compareTo * claimMultiplier;
|
|
2242
2392
|
switch (cond.operator) {
|
|
2393
|
+
case '==':
|
|
2394
|
+
return val === scaledCompareTo;
|
|
2395
|
+
case '!=':
|
|
2396
|
+
return val !== scaledCompareTo;
|
|
2243
2397
|
case '>':
|
|
2244
|
-
return val >
|
|
2398
|
+
return val > scaledCompareTo;
|
|
2245
2399
|
case '>=':
|
|
2246
|
-
return val >=
|
|
2400
|
+
return val >= scaledCompareTo;
|
|
2247
2401
|
case '<':
|
|
2248
|
-
return val <
|
|
2402
|
+
return val < scaledCompareTo;
|
|
2249
2403
|
case '<=':
|
|
2250
|
-
return val <=
|
|
2404
|
+
return val <= scaledCompareTo;
|
|
2251
2405
|
}
|
|
2252
2406
|
}
|
|
2253
2407
|
else if (!isNumber && typeof compareTo === 'string') {
|
|
2254
2408
|
switch (cond.operator) {
|
|
2409
|
+
case '==':
|
|
2410
|
+
return val === compareTo;
|
|
2411
|
+
case '!=':
|
|
2412
|
+
return val !== compareTo;
|
|
2255
2413
|
case 'has':
|
|
2256
2414
|
return val.includes(compareTo);
|
|
2257
2415
|
case 'not_has':
|
|
@@ -2260,24 +2418,119 @@ function evaluateDynamicCondition(dynamicObj, cond) {
|
|
|
2260
2418
|
}
|
|
2261
2419
|
return false;
|
|
2262
2420
|
}
|
|
2421
|
+
/**
|
|
2422
|
+
* Calculates the maximum number of claims supported by a single dynamic condition.
|
|
2423
|
+
*/
|
|
2424
|
+
function getMaxClaimsForDynamicCondition(dynamicObj, cond) {
|
|
2425
|
+
if (!dynamicObj)
|
|
2426
|
+
return 0;
|
|
2427
|
+
const val = dynamicObj[cond.key];
|
|
2428
|
+
if (val === undefined)
|
|
2429
|
+
return 0;
|
|
2430
|
+
if (typeof val === 'number') {
|
|
2431
|
+
const base = Number(cond.compareTo);
|
|
2432
|
+
if (isNaN(base)) {
|
|
2433
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2434
|
+
}
|
|
2435
|
+
switch (cond.operator) {
|
|
2436
|
+
case '>=':
|
|
2437
|
+
if (base === 0)
|
|
2438
|
+
return val >= 0 ? Infinity : 0;
|
|
2439
|
+
if (base < 0)
|
|
2440
|
+
return val >= base ? Infinity : 0;
|
|
2441
|
+
return Math.max(0, Math.floor(val / base));
|
|
2442
|
+
case '>':
|
|
2443
|
+
if (base === 0)
|
|
2444
|
+
return val > 0 ? Infinity : 0;
|
|
2445
|
+
if (base < 0)
|
|
2446
|
+
return val > base ? Infinity : 0;
|
|
2447
|
+
if (val <= 0)
|
|
2448
|
+
return 0;
|
|
2449
|
+
return Math.max(0, Math.ceil(val / base) - 1);
|
|
2450
|
+
case '==':
|
|
2451
|
+
return val === base ? Infinity : 0;
|
|
2452
|
+
case '!=':
|
|
2453
|
+
return val !== base ? Infinity : 0;
|
|
2454
|
+
case '<=':
|
|
2455
|
+
if (base === 0)
|
|
2456
|
+
return val <= 0 ? Infinity : 0;
|
|
2457
|
+
if (base > 0)
|
|
2458
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2459
|
+
if (val >= 0)
|
|
2460
|
+
return 0;
|
|
2461
|
+
return Math.max(0, Math.floor(val / base));
|
|
2462
|
+
case '<':
|
|
2463
|
+
if (base === 0)
|
|
2464
|
+
return val < 0 ? Infinity : 0;
|
|
2465
|
+
if (base > 0)
|
|
2466
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2467
|
+
if (val >= 0)
|
|
2468
|
+
return 0;
|
|
2469
|
+
return Math.max(0, Math.ceil(val / base) - 1);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
// we don't scale the rest, they are always true or always false
|
|
2473
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Calculates the maximum number of claims supported by a group of dynamic conditions.
|
|
2477
|
+
*/
|
|
2478
|
+
function getMaxClaimsForDynamicGroup(dynamicObj, dynamicGroup, currentClaimCount = 0) {
|
|
2479
|
+
const { conditions, links } = dynamicGroup;
|
|
2480
|
+
if (!conditions || conditions.length === 0)
|
|
2481
|
+
return Infinity;
|
|
2482
|
+
// AND only
|
|
2483
|
+
if (!links || links.length === 0 || links.every((l) => l === 'AND')) {
|
|
2484
|
+
let minClaims = Infinity;
|
|
2485
|
+
for (const cond of conditions) {
|
|
2486
|
+
const max = getMaxClaimsForDynamicCondition(dynamicObj, cond);
|
|
2487
|
+
if (max === 0)
|
|
2488
|
+
return 0;
|
|
2489
|
+
minClaims = Math.min(minClaims, max);
|
|
2490
|
+
}
|
|
2491
|
+
return minClaims;
|
|
2492
|
+
}
|
|
2493
|
+
// OR only
|
|
2494
|
+
if (links.every((l) => l === 'OR')) {
|
|
2495
|
+
let maxClaims = 0;
|
|
2496
|
+
for (const cond of conditions) {
|
|
2497
|
+
const max = getMaxClaimsForDynamicCondition(dynamicObj, cond);
|
|
2498
|
+
if (max === Infinity)
|
|
2499
|
+
return Infinity;
|
|
2500
|
+
maxClaims = Math.max(maxClaims, max);
|
|
2501
|
+
}
|
|
2502
|
+
return maxClaims;
|
|
2503
|
+
}
|
|
2504
|
+
// mixed:
|
|
2505
|
+
const maxIterations = 100;
|
|
2506
|
+
for (let n = currentClaimCount + 1; n <= currentClaimCount + maxIterations; n++) {
|
|
2507
|
+
if (!meetsDynamicConditions(dynamicObj, dynamicGroup, n)) {
|
|
2508
|
+
return n - 1;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
return currentClaimCount + maxIterations;
|
|
2512
|
+
}
|
|
2263
2513
|
/**
|
|
2264
2514
|
* Evaluates a group of dynamic conditions with logical links (AND, OR, AND NOT).
|
|
2265
2515
|
* @param dynamicObj - The player's dynamic object with any key and string or number value.
|
|
2266
2516
|
* @param dynamicGroup - The group of conditions and links to check.
|
|
2517
|
+
* @param claimMultiplier - Multiplier to scale conditions (used for numeric comparisons).
|
|
2267
2518
|
* @returns true if the group evaluates to true, false otherwise.
|
|
2268
2519
|
*/
|
|
2269
|
-
function meetsDynamicConditions(dynamicObj, dynamicGroup) {
|
|
2520
|
+
function meetsDynamicConditions(dynamicObj, dynamicGroup, claimMultiplier = 1) {
|
|
2270
2521
|
const { conditions, links } = dynamicGroup;
|
|
2271
2522
|
if (!conditions || conditions.length === 0)
|
|
2272
2523
|
return true;
|
|
2524
|
+
if (!dynamicObj)
|
|
2525
|
+
return false;
|
|
2273
2526
|
// If no links, treat as AND between all conditions
|
|
2274
2527
|
if (!links || links.length === 0) {
|
|
2275
|
-
return conditions.every((cond) => evaluateDynamicCondition(dynamicObj, cond));
|
|
2528
|
+
return conditions.every((cond) => evaluateDynamicCondition(dynamicObj, cond, claimMultiplier));
|
|
2276
2529
|
}
|
|
2277
2530
|
// Evaluate the first condition
|
|
2278
|
-
let result = evaluateDynamicCondition(dynamicObj, conditions[0]);
|
|
2531
|
+
let result = evaluateDynamicCondition(dynamicObj, conditions[0], claimMultiplier);
|
|
2279
2532
|
for (let i = 0; i < links.length; i++) {
|
|
2280
|
-
const nextCond = evaluateDynamicCondition(dynamicObj, conditions[i + 1]);
|
|
2533
|
+
const nextCond = evaluateDynamicCondition(dynamicObj, conditions[i + 1], claimMultiplier);
|
|
2281
2534
|
const link = links[i];
|
|
2282
2535
|
if (link === 'AND') {
|
|
2283
2536
|
result = result && nextCond;
|
|
@@ -2359,5 +2612,5 @@ const rewardSchema = {
|
|
|
2359
2612
|
image: String,
|
|
2360
2613
|
};
|
|
2361
2614
|
|
|
2362
|
-
export { AssetHelper, ConnectionState, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, hasConditions, meetsBaseConditions, meetsClaimableConditions, meetsCompletionConditions, meetsCompletionConditionsBeforeExpiry, meetsDynamicConditions, meetsSurfacingConditions, offerListenerEvents, rewardKinds, rewardSchema };
|
|
2615
|
+
export { AssetHelper, ConnectionState, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, getMaxClaimsForDynamicCondition, getMaxClaimsForDynamicGroup, hasConditions, meetsBaseConditions, meetsClaimableConditions, meetsCompletionConditions, meetsCompletionConditionsBeforeExpiry, meetsDynamicConditions, meetsSurfacingConditions, offerListenerEvents, offerMeetsCompletionConditions, rewardKinds, rewardSchema };
|
|
2363
2616
|
//# sourceMappingURL=index.esm.js.map
|