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