@pixels-online/pixels-client-js-sdk 1.16.0 → 1.17.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 +142 -33
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +142 -32
- package/dist/index.js.map +1 -1
- package/dist/offerwall-sdk.umd.js +142 -32
- 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 +36 -7
- package/dist/utils/template.d.ts +18 -1
- package/package.json +1 -1
|
@@ -1284,19 +1284,47 @@
|
|
|
1284
1284
|
}
|
|
1285
1285
|
|
|
1286
1286
|
const keyPattern = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
1287
|
-
|
|
1287
|
+
/**
|
|
1288
|
+
* This replaces {keyName} keys from the template with corresponding values from the dynamic object.
|
|
1289
|
+
*/
|
|
1288
1290
|
function renderTemplate(template, dynamic) {
|
|
1289
1291
|
if (!template)
|
|
1290
1292
|
return '';
|
|
1291
|
-
return template.replace(keyPattern, (
|
|
1293
|
+
return template.replace(keyPattern, (_match, key) => {
|
|
1294
|
+
if (dynamic && typeof dynamic[key] === 'boolean') {
|
|
1295
|
+
return dynamic[key] ? '✓' : '✗';
|
|
1296
|
+
}
|
|
1292
1297
|
if (dynamic && dynamic[key] !== undefined) {
|
|
1293
1298
|
return String(dynamic[key]);
|
|
1294
1299
|
}
|
|
1295
1300
|
return '{?}'; // indicate missing key
|
|
1296
1301
|
});
|
|
1297
1302
|
}
|
|
1303
|
+
/**
|
|
1304
|
+
* This replaces {{keyName}} in dynamic condition keys with corresponding values from
|
|
1305
|
+
* the PlayerOffer.trackers
|
|
1306
|
+
*
|
|
1307
|
+
* eg. a condition high_score_pet-{{surfacerPlayerId}} with high_score_pet-12345
|
|
1308
|
+
*/
|
|
1309
|
+
function replaceDynamicConditionKey(key, trackers) {
|
|
1310
|
+
return key?.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (match, p1) => {
|
|
1311
|
+
const value = trackers[p1];
|
|
1312
|
+
return value !== undefined ? String(value) : match;
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
/** this replaces all of the dynamic conditions.keys by calling replaceDynamicConditionKey */
|
|
1316
|
+
function replaceDynamicConditionKeys(conditions, trackers) {
|
|
1317
|
+
return conditions.map((condition) => ({
|
|
1318
|
+
...condition,
|
|
1319
|
+
key: replaceDynamicConditionKey(condition.key, trackers),
|
|
1320
|
+
}));
|
|
1321
|
+
}
|
|
1298
1322
|
|
|
1299
|
-
const meetsBaseConditions = ({ conditions, playerSnap, addDetails,
|
|
1323
|
+
const meetsBaseConditions = ({ conditions, playerSnap, addDetails,
|
|
1324
|
+
/** this exists if calling meetsBaseConditions from meetsCompletionConditions. but surfacing
|
|
1325
|
+
* check doesn't use this since we don't have a playerOffer at surfacing time
|
|
1326
|
+
*/
|
|
1327
|
+
playerOffer, }) => {
|
|
1300
1328
|
const conditionData = [];
|
|
1301
1329
|
let isValid = true;
|
|
1302
1330
|
if (conditions?.minDaysInGame) {
|
|
@@ -1663,7 +1691,11 @@
|
|
|
1663
1691
|
}
|
|
1664
1692
|
// Evaluate dynamic conditions
|
|
1665
1693
|
if (conditions?.dynamic?.conditions?.length) {
|
|
1666
|
-
const
|
|
1694
|
+
const resolvedConditions = replaceDynamicConditionKeys(conditions.dynamic.conditions, playerOffer?.trackers || {});
|
|
1695
|
+
const dynamicResult = meetsDynamicConditions(playerSnap.dynamic, {
|
|
1696
|
+
...conditions.dynamic,
|
|
1697
|
+
conditions: resolvedConditions,
|
|
1698
|
+
});
|
|
1667
1699
|
if (addDetails) {
|
|
1668
1700
|
conditionData.push({
|
|
1669
1701
|
isMet: dynamicResult,
|
|
@@ -1772,6 +1804,31 @@
|
|
|
1772
1804
|
return { isValid: false };
|
|
1773
1805
|
}
|
|
1774
1806
|
}
|
|
1807
|
+
if (conditions.allowedCountries?.length) {
|
|
1808
|
+
const playerCountry = playerSnap.ip?.countryCode;
|
|
1809
|
+
if (!playerCountry || !conditions.allowedCountries.includes(playerCountry)) {
|
|
1810
|
+
return { isValid: false };
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
if (conditions.restrictedCountries?.length) {
|
|
1814
|
+
const playerCountry = playerSnap.ip?.countryCode;
|
|
1815
|
+
if (!playerCountry) {
|
|
1816
|
+
return { isValid: false };
|
|
1817
|
+
}
|
|
1818
|
+
if (conditions.restrictedCountries.includes(playerCountry)) {
|
|
1819
|
+
return { isValid: false };
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
if (conditions.networkRestrictions?.length) {
|
|
1823
|
+
if (!playerSnap.ip) {
|
|
1824
|
+
return { isValid: false };
|
|
1825
|
+
}
|
|
1826
|
+
for (const restriction of conditions.networkRestrictions) {
|
|
1827
|
+
if (playerSnap.ip[restriction]) {
|
|
1828
|
+
return { isValid: false };
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1775
1832
|
return meetsBaseConditions({ conditions, playerSnap });
|
|
1776
1833
|
};
|
|
1777
1834
|
const hasConditions = (conditions) => {
|
|
@@ -1824,6 +1881,12 @@
|
|
|
1824
1881
|
return true;
|
|
1825
1882
|
if (surCond.links && Object.keys(surCond.links).length > 0)
|
|
1826
1883
|
return true;
|
|
1884
|
+
if (surCond.allowedCountries?.length)
|
|
1885
|
+
return true;
|
|
1886
|
+
if (surCond.restrictedCountries?.length)
|
|
1887
|
+
return true;
|
|
1888
|
+
if (surCond.networkRestrictions?.length)
|
|
1889
|
+
return true;
|
|
1827
1890
|
const compCond = conditions;
|
|
1828
1891
|
if (compCond.context)
|
|
1829
1892
|
return true;
|
|
@@ -1845,9 +1908,21 @@
|
|
|
1845
1908
|
return true;
|
|
1846
1909
|
return false;
|
|
1847
1910
|
};
|
|
1848
|
-
const
|
|
1911
|
+
const offerMeetsCompletionConditions = (offer, snapshot) => {
|
|
1912
|
+
return meetsCompletionConditions({
|
|
1913
|
+
completionConditions: offer.completionConditions || {},
|
|
1914
|
+
completionTrackers: offer.completionTrackers,
|
|
1915
|
+
playerSnap: snapshot,
|
|
1916
|
+
playerOffer: offer,
|
|
1917
|
+
addDetails: true,
|
|
1918
|
+
});
|
|
1919
|
+
};
|
|
1920
|
+
const meetsCompletionConditions = ({ completionConditions, completionTrackers, playerSnap, playerOffer, addDetails = false, maxClaimCount, }) => {
|
|
1849
1921
|
if (completionConditions) {
|
|
1850
1922
|
const conditions = completionConditions;
|
|
1923
|
+
// For multi-claim offers, scale cumulative requirements by (claimedCount + 1)
|
|
1924
|
+
const shouldScale = maxClaimCount === -1 || (maxClaimCount && maxClaimCount > 1);
|
|
1925
|
+
const claimMultiplier = shouldScale ? (playerOffer.claimedCount || 0) + 1 : 1;
|
|
1851
1926
|
const conditionData = [];
|
|
1852
1927
|
let isValid = true;
|
|
1853
1928
|
if (completionConditions?.context?.id) {
|
|
@@ -1870,13 +1945,14 @@
|
|
|
1870
1945
|
}
|
|
1871
1946
|
}
|
|
1872
1947
|
if (conditions?.buyItem) {
|
|
1873
|
-
const
|
|
1948
|
+
const scaledAmount = (conditions.buyItem.amount || 1) * claimMultiplier;
|
|
1949
|
+
const isDisqualify = (completionTrackers?.buyItem || 0) < scaledAmount;
|
|
1874
1950
|
if (addDetails) {
|
|
1875
1951
|
conditionData.push({
|
|
1876
1952
|
isMet: !isDisqualify,
|
|
1877
1953
|
kind: 'buyItem',
|
|
1878
1954
|
trackerAmount: completionTrackers?.buyItem || 0,
|
|
1879
|
-
text: `Buy ${
|
|
1955
|
+
text: `Buy ${scaledAmount} ${conditions.buyItem.name}`,
|
|
1880
1956
|
});
|
|
1881
1957
|
if (isDisqualify)
|
|
1882
1958
|
isValid = false;
|
|
@@ -1887,13 +1963,14 @@
|
|
|
1887
1963
|
}
|
|
1888
1964
|
}
|
|
1889
1965
|
if (conditions?.spendCurrency) {
|
|
1890
|
-
const
|
|
1966
|
+
const scaledAmount = (conditions.spendCurrency.amount || 1) * claimMultiplier;
|
|
1967
|
+
const isDisqualify = (completionTrackers?.spendCurrency || 0) < scaledAmount;
|
|
1891
1968
|
if (addDetails) {
|
|
1892
1969
|
conditionData.push({
|
|
1893
1970
|
isMet: !isDisqualify,
|
|
1894
1971
|
kind: 'spendCurrency',
|
|
1895
1972
|
trackerAmount: completionTrackers?.spendCurrency || 0,
|
|
1896
|
-
text: `Spend ${
|
|
1973
|
+
text: `Spend ${scaledAmount} ${conditions.spendCurrency.name}`,
|
|
1897
1974
|
});
|
|
1898
1975
|
if (isDisqualify)
|
|
1899
1976
|
isValid = false;
|
|
@@ -1904,15 +1981,17 @@
|
|
|
1904
1981
|
}
|
|
1905
1982
|
}
|
|
1906
1983
|
if (conditions?.depositCurrency) {
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1984
|
+
const scaledAmount = (conditions.depositCurrency.amount || 1) * claimMultiplier;
|
|
1985
|
+
const isDisqualify = (completionTrackers?.depositCurrency || 0) < scaledAmount;
|
|
1909
1986
|
if (addDetails) {
|
|
1910
1987
|
conditionData.push({
|
|
1911
1988
|
isMet: !isDisqualify,
|
|
1912
1989
|
kind: 'depositCurrency',
|
|
1913
1990
|
trackerAmount: completionTrackers?.depositCurrency || 0,
|
|
1914
|
-
text: `Deposit ${
|
|
1991
|
+
text: `Deposit ${scaledAmount} ${conditions.depositCurrency.name}`,
|
|
1915
1992
|
});
|
|
1993
|
+
if (isDisqualify)
|
|
1994
|
+
isValid = false;
|
|
1916
1995
|
}
|
|
1917
1996
|
else {
|
|
1918
1997
|
if (isDisqualify)
|
|
@@ -1920,12 +1999,13 @@
|
|
|
1920
1999
|
}
|
|
1921
2000
|
}
|
|
1922
2001
|
if (conditions?.login) {
|
|
1923
|
-
const isMet =
|
|
2002
|
+
const isMet = new Date(playerSnap.snapshotLastUpdated || 0).getTime() >
|
|
2003
|
+
new Date(playerOffer.createdAt || 0).getTime();
|
|
1924
2004
|
if (addDetails) {
|
|
1925
2005
|
conditionData.push({
|
|
1926
2006
|
isMet,
|
|
1927
2007
|
kind: 'login',
|
|
1928
|
-
trackerAmount:
|
|
2008
|
+
trackerAmount: isMet ? 1 : 0,
|
|
1929
2009
|
text: `Login to the game`,
|
|
1930
2010
|
});
|
|
1931
2011
|
isValid = isMet;
|
|
@@ -1962,9 +2042,11 @@
|
|
|
1962
2042
|
const hasContent = Boolean(mode === 'accumulate'
|
|
1963
2043
|
? tSocial?.mode === 'accumulate'
|
|
1964
2044
|
: tSocial && tSocial.mode !== 'accumulate' && !!tSocial.videoId);
|
|
1965
|
-
|
|
1966
|
-
const
|
|
1967
|
-
const
|
|
2045
|
+
// Only scale social metrics in accumulate mode (attach mode is single content)
|
|
2046
|
+
const socialMultiplier = mode === 'accumulate' ? claimMultiplier : 1;
|
|
2047
|
+
const minLikes = (cSocial?.minLikes || 0) * socialMultiplier;
|
|
2048
|
+
const minViews = (cSocial?.minViews || 0) * socialMultiplier;
|
|
2049
|
+
const minComments = (cSocial?.minComments || 0) * socialMultiplier;
|
|
1968
2050
|
const likes = tSocial?.likes || 0;
|
|
1969
2051
|
const views = tSocial?.views || 0;
|
|
1970
2052
|
const comments = tSocial?.comments || 0;
|
|
@@ -2049,14 +2131,14 @@
|
|
|
2049
2131
|
// Linked completions - wait for N linked entities to complete
|
|
2050
2132
|
if (conditions?.linkedCompletions?.min) {
|
|
2051
2133
|
const currentCount = completionTrackers?.linkedCompletions || 0;
|
|
2052
|
-
const
|
|
2053
|
-
const isDisqualify = currentCount <
|
|
2134
|
+
const scaledMin = conditions.linkedCompletions.min * claimMultiplier;
|
|
2135
|
+
const isDisqualify = currentCount < scaledMin;
|
|
2054
2136
|
if (addDetails) {
|
|
2055
2137
|
conditionData.push({
|
|
2056
2138
|
isMet: !isDisqualify,
|
|
2057
2139
|
kind: 'linkedCompletions',
|
|
2058
2140
|
trackerAmount: currentCount,
|
|
2059
|
-
text: `Wait for ${
|
|
2141
|
+
text: `Wait for ${scaledMin} linked ${scaledMin === 1 ? 'entity' : 'entities'} to complete`,
|
|
2060
2142
|
});
|
|
2061
2143
|
if (isDisqualify)
|
|
2062
2144
|
isValid = false;
|
|
@@ -2067,7 +2149,12 @@
|
|
|
2067
2149
|
}
|
|
2068
2150
|
}
|
|
2069
2151
|
if (conditions?.dynamicTracker?.conditions?.length) {
|
|
2070
|
-
const
|
|
2152
|
+
const resolvedConditions = replaceDynamicConditionKeys(conditions.dynamicTracker.conditions, playerOffer?.trackers || {});
|
|
2153
|
+
// now we have the game-defined conditions with {{}} keys populated. feed these conditions into evaluator
|
|
2154
|
+
const dynamicResult = meetsDynamicConditions(completionTrackers?.dynamicTracker, {
|
|
2155
|
+
...conditions.dynamicTracker,
|
|
2156
|
+
conditions: resolvedConditions,
|
|
2157
|
+
}, claimMultiplier);
|
|
2071
2158
|
if (addDetails) {
|
|
2072
2159
|
conditionData.push({
|
|
2073
2160
|
isMet: dynamicResult,
|
|
@@ -2086,6 +2173,7 @@
|
|
|
2086
2173
|
conditions,
|
|
2087
2174
|
playerSnap,
|
|
2088
2175
|
addDetails: true,
|
|
2176
|
+
playerOffer,
|
|
2089
2177
|
});
|
|
2090
2178
|
isValid = isValid && r.isValid;
|
|
2091
2179
|
conditionData.push(...(r.conditionData || []));
|
|
@@ -2100,10 +2188,9 @@
|
|
|
2100
2188
|
* @param completionConditions - The completion conditions to check
|
|
2101
2189
|
* @param completionTrackers - The completion trackers (for buyItem, spendCurrency, etc.)
|
|
2102
2190
|
* @param playerSnap - The player snapshot with field timestamps
|
|
2103
|
-
* @param expiryTime - The expiry timestamp in milliseconds
|
|
2104
2191
|
* @returns true if all conditions were met before expiry, false otherwise
|
|
2105
2192
|
*/
|
|
2106
|
-
const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completionTrackers, playerSnap,
|
|
2193
|
+
const meetsCompletionConditionsBeforeExpiry = ({ completionConditions, completionTrackers, playerSnap, playerOffer, maxClaimCount, }) => {
|
|
2107
2194
|
if (!completionConditions)
|
|
2108
2195
|
return false;
|
|
2109
2196
|
// Check if there are actually any conditions to evaluate
|
|
@@ -2113,10 +2200,15 @@
|
|
|
2113
2200
|
const conditionsMet = meetsCompletionConditions({
|
|
2114
2201
|
completionConditions,
|
|
2115
2202
|
completionTrackers,
|
|
2203
|
+
playerOffer,
|
|
2116
2204
|
playerSnap,
|
|
2205
|
+
maxClaimCount,
|
|
2117
2206
|
});
|
|
2118
2207
|
if (!conditionsMet.isValid)
|
|
2119
2208
|
return false;
|
|
2209
|
+
if (!playerOffer.expiresAt)
|
|
2210
|
+
return true;
|
|
2211
|
+
const expiryTime = new Date(playerOffer.expiresAt).getTime();
|
|
2120
2212
|
const lastSnapshotUpdate = new Date(playerSnap.snapshotLastUpdated).getTime();
|
|
2121
2213
|
/**
|
|
2122
2214
|
* Checks if a field was updated after the expiry time.
|
|
@@ -2227,16 +2319,30 @@
|
|
|
2227
2319
|
* Checks if a dynamic object meets a set of dynamic field conditions.
|
|
2228
2320
|
* @param dynamicObj - The object with any key and string or number value.
|
|
2229
2321
|
* @param conditions - Array of conditions to check.
|
|
2322
|
+
* @param claimMultiplier - Multiplier to scale conditions (used for numeric comparisons).
|
|
2230
2323
|
* @returns true if all conditions are met, false otherwise.
|
|
2231
2324
|
*/
|
|
2232
2325
|
/**
|
|
2233
2326
|
* Evaluates a single dynamic condition against the dynamic object.
|
|
2234
2327
|
*/
|
|
2235
|
-
function evaluateDynamicCondition(dynamicObj, cond) {
|
|
2328
|
+
function evaluateDynamicCondition(dynamicObj, cond, claimMultiplier = 1) {
|
|
2329
|
+
if (!dynamicObj)
|
|
2330
|
+
return false;
|
|
2236
2331
|
const val = dynamicObj[cond.key];
|
|
2237
2332
|
if (val === undefined)
|
|
2238
2333
|
return false;
|
|
2239
2334
|
const isNumber = typeof val === 'number';
|
|
2335
|
+
const isBoolean = typeof val === 'boolean';
|
|
2336
|
+
if (isBoolean) {
|
|
2337
|
+
switch (cond.operator) {
|
|
2338
|
+
case '==':
|
|
2339
|
+
return val === Boolean(cond.compareTo);
|
|
2340
|
+
case '!=':
|
|
2341
|
+
return val !== Boolean(cond.compareTo);
|
|
2342
|
+
default:
|
|
2343
|
+
return false;
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2240
2346
|
const compareTo = isNumber ? Number(cond.compareTo) : String(cond.compareTo);
|
|
2241
2347
|
switch (cond.operator) {
|
|
2242
2348
|
case '==':
|
|
@@ -2247,13 +2353,13 @@
|
|
|
2247
2353
|
if (isNumber && typeof compareTo === 'number') {
|
|
2248
2354
|
switch (cond.operator) {
|
|
2249
2355
|
case '>':
|
|
2250
|
-
return val > compareTo;
|
|
2356
|
+
return val > compareTo * claimMultiplier;
|
|
2251
2357
|
case '>=':
|
|
2252
|
-
return val >= compareTo;
|
|
2358
|
+
return val >= compareTo * claimMultiplier;
|
|
2253
2359
|
case '<':
|
|
2254
|
-
return val < compareTo;
|
|
2360
|
+
return val < compareTo * claimMultiplier;
|
|
2255
2361
|
case '<=':
|
|
2256
|
-
return val <= compareTo;
|
|
2362
|
+
return val <= compareTo * claimMultiplier;
|
|
2257
2363
|
}
|
|
2258
2364
|
}
|
|
2259
2365
|
else if (!isNumber && typeof compareTo === 'string') {
|
|
@@ -2270,20 +2376,23 @@
|
|
|
2270
2376
|
* Evaluates a group of dynamic conditions with logical links (AND, OR, AND NOT).
|
|
2271
2377
|
* @param dynamicObj - The player's dynamic object with any key and string or number value.
|
|
2272
2378
|
* @param dynamicGroup - The group of conditions and links to check.
|
|
2379
|
+
* @param claimMultiplier - Multiplier to scale conditions (used for numeric comparisons).
|
|
2273
2380
|
* @returns true if the group evaluates to true, false otherwise.
|
|
2274
2381
|
*/
|
|
2275
|
-
function meetsDynamicConditions(dynamicObj, dynamicGroup) {
|
|
2382
|
+
function meetsDynamicConditions(dynamicObj, dynamicGroup, claimMultiplier = 1) {
|
|
2276
2383
|
const { conditions, links } = dynamicGroup;
|
|
2277
2384
|
if (!conditions || conditions.length === 0)
|
|
2278
2385
|
return true;
|
|
2386
|
+
if (!dynamicObj)
|
|
2387
|
+
return false;
|
|
2279
2388
|
// If no links, treat as AND between all conditions
|
|
2280
2389
|
if (!links || links.length === 0) {
|
|
2281
|
-
return conditions.every((cond) => evaluateDynamicCondition(dynamicObj, cond));
|
|
2390
|
+
return conditions.every((cond) => evaluateDynamicCondition(dynamicObj, cond, claimMultiplier));
|
|
2282
2391
|
}
|
|
2283
2392
|
// Evaluate the first condition
|
|
2284
|
-
let result = evaluateDynamicCondition(dynamicObj, conditions[0]);
|
|
2393
|
+
let result = evaluateDynamicCondition(dynamicObj, conditions[0], claimMultiplier);
|
|
2285
2394
|
for (let i = 0; i < links.length; i++) {
|
|
2286
|
-
const nextCond = evaluateDynamicCondition(dynamicObj, conditions[i + 1]);
|
|
2395
|
+
const nextCond = evaluateDynamicCondition(dynamicObj, conditions[i + 1], claimMultiplier);
|
|
2287
2396
|
const link = links[i];
|
|
2288
2397
|
if (link === 'AND') {
|
|
2289
2398
|
result = result && nextCond;
|
|
@@ -2379,6 +2488,7 @@
|
|
|
2379
2488
|
exports.meetsDynamicConditions = meetsDynamicConditions;
|
|
2380
2489
|
exports.meetsSurfacingConditions = meetsSurfacingConditions;
|
|
2381
2490
|
exports.offerListenerEvents = offerListenerEvents;
|
|
2491
|
+
exports.offerMeetsCompletionConditions = offerMeetsCompletionConditions;
|
|
2382
2492
|
exports.rewardKinds = rewardKinds;
|
|
2383
2493
|
exports.rewardSchema = rewardSchema;
|
|
2384
2494
|
|