@pixels-online/pixels-client-js-sdk 1.17.0 → 1.19.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/core/OfferStore.d.ts +20 -14
- package/dist/core/OfferwallClient.d.ts +6 -4
- package/dist/index.esm.js +265 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +266 -77
- package/dist/index.js.map +1 -1
- package/dist/offerwall-sdk.umd.js +266 -77
- package/dist/offerwall-sdk.umd.js.map +1 -1
- package/dist/utils/conditions.d.ts +13 -1
- package/package.json +1 -1
|
@@ -634,25 +634,33 @@
|
|
|
634
634
|
}
|
|
635
635
|
|
|
636
636
|
class OfferStore {
|
|
637
|
-
constructor(config) {
|
|
637
|
+
constructor(config, client) {
|
|
638
|
+
this.client = client;
|
|
638
639
|
this.offers = new Map();
|
|
639
|
-
this.
|
|
640
|
+
this.players = new Map();
|
|
640
641
|
this.logger = createLogger(config, 'OfferStore');
|
|
641
642
|
}
|
|
642
|
-
getPlayer() {
|
|
643
|
-
|
|
643
|
+
getPlayer(targetId = this.client.getSelfId()) {
|
|
644
|
+
if (!targetId)
|
|
645
|
+
return null;
|
|
646
|
+
return this.players.get(targetId) || null;
|
|
644
647
|
}
|
|
645
648
|
setPlayer(player) {
|
|
646
|
-
this.player
|
|
649
|
+
this.players.set(player.snapshot.playerId, player);
|
|
647
650
|
this.logger.log('Updated player:', player);
|
|
648
651
|
}
|
|
649
652
|
/**
|
|
650
653
|
* Set all offers (replaces existing)
|
|
651
654
|
*/
|
|
652
|
-
setOffers(offers) {
|
|
653
|
-
this.
|
|
655
|
+
setOffers(offers, target) {
|
|
656
|
+
const targetPlayer = target || this.getPlayer();
|
|
657
|
+
if (!targetPlayer) {
|
|
658
|
+
this.logger.warn('No target player to set offers for');
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
this.offers.set(targetPlayer.snapshot.playerId, new Map());
|
|
654
662
|
offers.forEach((offer) => {
|
|
655
|
-
this.offers.set(offer.instanceId, offer);
|
|
663
|
+
this.offers.get(targetPlayer.snapshot.playerId).set(offer.instanceId, offer);
|
|
656
664
|
});
|
|
657
665
|
this.logger.log(`Set ${offers.length} offers`);
|
|
658
666
|
}
|
|
@@ -660,16 +668,23 @@
|
|
|
660
668
|
* Add or update a single offer
|
|
661
669
|
*/
|
|
662
670
|
upsertOffer(offer) {
|
|
663
|
-
|
|
664
|
-
|
|
671
|
+
let playerOffers = this.offers.get(offer.playerId);
|
|
672
|
+
if (!playerOffers) {
|
|
673
|
+
playerOffers = new Map();
|
|
674
|
+
this.offers.set(offer.playerId, playerOffers);
|
|
675
|
+
}
|
|
676
|
+
const previousOffer = playerOffers.get(offer.instanceId);
|
|
677
|
+
playerOffers.set(offer.instanceId, offer);
|
|
665
678
|
this.logger.log(`${previousOffer ? 'Updated' : 'Added'} offer:`, offer.instanceId);
|
|
666
679
|
return previousOffer;
|
|
667
680
|
}
|
|
668
681
|
/**
|
|
669
682
|
* Remove an offer
|
|
670
683
|
*/
|
|
671
|
-
removeOffer(offerId) {
|
|
672
|
-
|
|
684
|
+
removeOffer(offerId, targetId = this.client.getSelfId()) {
|
|
685
|
+
if (!targetId)
|
|
686
|
+
return false;
|
|
687
|
+
const removed = this.offers.get(targetId)?.delete(offerId) || false;
|
|
673
688
|
if (removed) {
|
|
674
689
|
this.logger.log(`Removed offer:`, offerId);
|
|
675
690
|
}
|
|
@@ -678,26 +693,30 @@
|
|
|
678
693
|
/**
|
|
679
694
|
* Get a single offer
|
|
680
695
|
*/
|
|
681
|
-
getOffer(offerId) {
|
|
682
|
-
|
|
696
|
+
getOffer(offerId, targetId = this.client.getSelfId()) {
|
|
697
|
+
if (!targetId)
|
|
698
|
+
return undefined;
|
|
699
|
+
return this.offers.get(targetId)?.get(offerId);
|
|
683
700
|
}
|
|
684
701
|
/**
|
|
685
702
|
* Get all offers
|
|
686
703
|
*/
|
|
687
|
-
getAllOffers() {
|
|
688
|
-
|
|
704
|
+
getAllOffers(targetId = this.client.getSelfId()) {
|
|
705
|
+
if (!targetId)
|
|
706
|
+
return [];
|
|
707
|
+
return Array.from(this.offers.get(targetId)?.values() || []);
|
|
689
708
|
}
|
|
690
709
|
/**
|
|
691
710
|
* Get offers filtered by status
|
|
692
711
|
*/
|
|
693
|
-
getOffersByStatus(status) {
|
|
694
|
-
return this.getAllOffers().filter((offer) => offer.status === status);
|
|
712
|
+
getOffersByStatus(status, targetId = this.client.getSelfId()) {
|
|
713
|
+
return this.getAllOffers(targetId).filter((offer) => offer.status === status);
|
|
695
714
|
}
|
|
696
715
|
/**
|
|
697
716
|
* Get active offers (not expired, not claimed)
|
|
698
717
|
*/
|
|
699
|
-
getActiveOffers() {
|
|
700
|
-
return this.getAllOffers().filter((offer) => {
|
|
718
|
+
getActiveOffers(targetId = this.client.getSelfId()) {
|
|
719
|
+
return this.getAllOffers(targetId).filter((offer) => {
|
|
701
720
|
if (!offer.status)
|
|
702
721
|
return false; // Must have a status
|
|
703
722
|
return (offer.status === 'surfaced' ||
|
|
@@ -708,14 +727,14 @@
|
|
|
708
727
|
/**
|
|
709
728
|
* Get claimable offers
|
|
710
729
|
*/
|
|
711
|
-
getClaimableOffers() {
|
|
712
|
-
return this.getOffersByStatus('claimable');
|
|
730
|
+
getClaimableOffers(targetId = this.client.getSelfId()) {
|
|
731
|
+
return this.getOffersByStatus('claimable', targetId);
|
|
713
732
|
}
|
|
714
733
|
/**
|
|
715
734
|
* Check if an offer has expired
|
|
716
735
|
*/
|
|
717
|
-
isOfferExpired(offerId) {
|
|
718
|
-
const offer = this.getOffer(offerId);
|
|
736
|
+
isOfferExpired(offerId, targetId = this.client.getSelfId()) {
|
|
737
|
+
const offer = this.getOffer(offerId, targetId);
|
|
719
738
|
if (!offer)
|
|
720
739
|
return true;
|
|
721
740
|
// Check status
|
|
@@ -728,17 +747,29 @@
|
|
|
728
747
|
return false;
|
|
729
748
|
}
|
|
730
749
|
/**
|
|
731
|
-
* Clear all offers
|
|
750
|
+
* Clear all offers for a specific player
|
|
732
751
|
*/
|
|
733
|
-
clear() {
|
|
752
|
+
clear(targetId = this.client.getSelfId()) {
|
|
753
|
+
if (!targetId)
|
|
754
|
+
return;
|
|
755
|
+
this.offers.set(targetId, new Map());
|
|
756
|
+
this.logger.log('Cleared all offers for player:', targetId);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Clear all offers for all players
|
|
760
|
+
*/
|
|
761
|
+
clearAll() {
|
|
734
762
|
this.offers.clear();
|
|
735
|
-
this.logger.log('Cleared all offers');
|
|
763
|
+
this.logger.log('Cleared all offers for all players');
|
|
736
764
|
}
|
|
737
765
|
/**
|
|
738
|
-
* Get offer count
|
|
766
|
+
* Get offer count (for self player)
|
|
739
767
|
*/
|
|
740
768
|
get size() {
|
|
741
|
-
|
|
769
|
+
const selfId = this.client.getSelfId();
|
|
770
|
+
if (!selfId)
|
|
771
|
+
return 0;
|
|
772
|
+
return this.offers.get(selfId)?.size || 0;
|
|
742
773
|
}
|
|
743
774
|
}
|
|
744
775
|
|
|
@@ -841,7 +872,9 @@
|
|
|
841
872
|
return null;
|
|
842
873
|
}
|
|
843
874
|
setCurrencyAssetContents(currencies) {
|
|
844
|
-
|
|
875
|
+
Object.keys(currencies).forEach((key) => {
|
|
876
|
+
this.currencies[key] = currencies[key];
|
|
877
|
+
});
|
|
845
878
|
}
|
|
846
879
|
resolveReward(reward) {
|
|
847
880
|
if (reward.kind === 'loyalty_currency' && reward.rewardId) {
|
|
@@ -897,6 +930,7 @@
|
|
|
897
930
|
constructor(config) {
|
|
898
931
|
this.isInitializing = false;
|
|
899
932
|
this.pendingStackedToken = null;
|
|
933
|
+
this.selfId = null;
|
|
900
934
|
this.config = {
|
|
901
935
|
autoConnect: config.autoConnect ?? false,
|
|
902
936
|
reconnect: config.reconnect ?? true,
|
|
@@ -909,7 +943,7 @@
|
|
|
909
943
|
this.hooks = this.config.hooks || {};
|
|
910
944
|
this.logger = createLogger(this.config, 'OfferwallClient');
|
|
911
945
|
this.eventEmitter = new EventEmitter(this.config);
|
|
912
|
-
this.offerStore = new OfferStore(this.config);
|
|
946
|
+
this.offerStore = new OfferStore(this.config, this);
|
|
913
947
|
this.tokenManager = new TokenManager(this.config);
|
|
914
948
|
this.assetHelper = new AssetHelper(this.config);
|
|
915
949
|
this.sseConnection = new SSEConnection(this.config, this.eventEmitter, this.tokenManager);
|
|
@@ -950,6 +984,9 @@
|
|
|
950
984
|
get assets() {
|
|
951
985
|
return this.assetHelper;
|
|
952
986
|
}
|
|
987
|
+
getSelfId() {
|
|
988
|
+
return this.selfId;
|
|
989
|
+
}
|
|
953
990
|
/**
|
|
954
991
|
* Initialize the offerwall client and connect
|
|
955
992
|
*/
|
|
@@ -1012,8 +1049,9 @@
|
|
|
1012
1049
|
if (this.sseConnection) {
|
|
1013
1050
|
this.sseConnection.disconnect();
|
|
1014
1051
|
}
|
|
1015
|
-
this.offerStore.
|
|
1052
|
+
this.offerStore.clearAll();
|
|
1016
1053
|
this.tokenManager.clearToken();
|
|
1054
|
+
this.selfId = null;
|
|
1017
1055
|
if (this.hooks.afterDisconnect) {
|
|
1018
1056
|
await this.hooks.afterDisconnect();
|
|
1019
1057
|
}
|
|
@@ -1021,8 +1059,8 @@
|
|
|
1021
1059
|
/**
|
|
1022
1060
|
* Claim rewards for an offer
|
|
1023
1061
|
*/
|
|
1024
|
-
async claimReward(instanceId) {
|
|
1025
|
-
const offer = this.offerStore.getOffer(instanceId);
|
|
1062
|
+
async claimReward(instanceId, targetId = this.getSelfId()) {
|
|
1063
|
+
const offer = this.offerStore.getOffer(instanceId, targetId);
|
|
1026
1064
|
if (!offer) {
|
|
1027
1065
|
throw new Error(`Offer ${instanceId} not found`);
|
|
1028
1066
|
}
|
|
@@ -1037,7 +1075,7 @@
|
|
|
1037
1075
|
}
|
|
1038
1076
|
}
|
|
1039
1077
|
try {
|
|
1040
|
-
const response = await this.claimOfferAPI(instanceId);
|
|
1078
|
+
const response = await this.claimOfferAPI(instanceId, targetId);
|
|
1041
1079
|
const updatedOffer = { ...offer, status: 'claimed' };
|
|
1042
1080
|
this.offerStore.upsertOffer(updatedOffer);
|
|
1043
1081
|
this.eventEmitter.emit(exports.OfferEvent.OFFER_CLAIMED, {
|
|
@@ -1093,7 +1131,7 @@
|
|
|
1093
1131
|
});
|
|
1094
1132
|
*/
|
|
1095
1133
|
this.eventEmitter.on(exports.OfferEvent.OFFER_SURFACED, ({ offer }) => {
|
|
1096
|
-
this.offerStore.upsertOffer(offer);
|
|
1134
|
+
this.offerStore.upsertOffer(offer); // should always be selfId
|
|
1097
1135
|
this.logger.log(`Surfaced offer: ${offer.instanceId}`);
|
|
1098
1136
|
});
|
|
1099
1137
|
}
|
|
@@ -1123,23 +1161,27 @@
|
|
|
1123
1161
|
}
|
|
1124
1162
|
return response.json();
|
|
1125
1163
|
}
|
|
1126
|
-
async claimOfferAPI(instanceId) {
|
|
1164
|
+
async claimOfferAPI(instanceId, targetId = null) {
|
|
1127
1165
|
return this.postWithAuth('/v1/client/reward/claim', {
|
|
1128
1166
|
instanceId,
|
|
1129
1167
|
kind: 'offer',
|
|
1168
|
+
targetId: targetId || undefined,
|
|
1130
1169
|
});
|
|
1131
1170
|
}
|
|
1132
|
-
getPlayer() {
|
|
1133
|
-
return this.offerStore.getPlayer();
|
|
1171
|
+
getPlayer(targetId = this.getSelfId()) {
|
|
1172
|
+
return this.offerStore.getPlayer(targetId);
|
|
1134
1173
|
}
|
|
1135
|
-
getOffers() {
|
|
1136
|
-
return this.offerStore.getAllOffers();
|
|
1174
|
+
getOffers(targetId = this.getSelfId()) {
|
|
1175
|
+
return this.offerStore.getAllOffers(targetId);
|
|
1137
1176
|
}
|
|
1138
|
-
async refreshOffersAndPlayer() {
|
|
1177
|
+
async refreshOffersAndPlayer(targetId = null) {
|
|
1139
1178
|
try {
|
|
1140
|
-
const { offers, player } = await this.getOffersAndPlayer();
|
|
1141
|
-
|
|
1179
|
+
const { offers, player } = await this.getOffersAndPlayer(targetId);
|
|
1180
|
+
if (targetId == null) {
|
|
1181
|
+
this.selfId = player.snapshot.playerId;
|
|
1182
|
+
}
|
|
1142
1183
|
this.offerStore.setPlayer(player);
|
|
1184
|
+
this.offerStore.setOffers(offers, player);
|
|
1143
1185
|
this.eventEmitter.emit(exports.OfferEvent.REFRESH, { offers, player: player });
|
|
1144
1186
|
this.logger.log('Refreshed offers and player snapshot');
|
|
1145
1187
|
}
|
|
@@ -1148,9 +1190,10 @@
|
|
|
1148
1190
|
throw error;
|
|
1149
1191
|
}
|
|
1150
1192
|
}
|
|
1151
|
-
async getOffersAndPlayer() {
|
|
1193
|
+
async getOffersAndPlayer(targetId = null) {
|
|
1152
1194
|
const data = await this.postWithAuth('/v1/client/player/campaigns', {
|
|
1153
1195
|
viewingCampaigns: true,
|
|
1196
|
+
targetId: targetId || undefined,
|
|
1154
1197
|
});
|
|
1155
1198
|
if (!data.offers || !Array.isArray(data.offers)) {
|
|
1156
1199
|
throw new Error('No offers returned from offers endpoint');
|
|
@@ -1925,6 +1968,8 @@
|
|
|
1925
1968
|
const claimMultiplier = shouldScale ? (playerOffer.claimedCount || 0) + 1 : 1;
|
|
1926
1969
|
const conditionData = [];
|
|
1927
1970
|
let isValid = true;
|
|
1971
|
+
let maxTotalClaimsFromScaling = Infinity;
|
|
1972
|
+
const updateMax = (limit) => (maxTotalClaimsFromScaling = Math.min(maxTotalClaimsFromScaling, limit));
|
|
1928
1973
|
if (completionConditions?.context?.id) {
|
|
1929
1974
|
const hasTrackedContext = completionTrackers?.context &&
|
|
1930
1975
|
completionConditions.context.id === completionTrackers.context;
|
|
@@ -1941,17 +1986,22 @@
|
|
|
1941
1986
|
}
|
|
1942
1987
|
else {
|
|
1943
1988
|
if (isDisqualify)
|
|
1944
|
-
return { isValid: false };
|
|
1989
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1945
1990
|
}
|
|
1946
1991
|
}
|
|
1947
1992
|
if (conditions?.buyItem) {
|
|
1948
|
-
const
|
|
1949
|
-
const
|
|
1993
|
+
const baseAmount = conditions.buyItem.amount || 1;
|
|
1994
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
1995
|
+
const trackerValue = completionTrackers?.buyItem || 0;
|
|
1996
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
1997
|
+
if (shouldScale && baseAmount > 0) {
|
|
1998
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
1999
|
+
}
|
|
1950
2000
|
if (addDetails) {
|
|
1951
2001
|
conditionData.push({
|
|
1952
2002
|
isMet: !isDisqualify,
|
|
1953
2003
|
kind: 'buyItem',
|
|
1954
|
-
trackerAmount:
|
|
2004
|
+
trackerAmount: trackerValue,
|
|
1955
2005
|
text: `Buy ${scaledAmount} ${conditions.buyItem.name}`,
|
|
1956
2006
|
});
|
|
1957
2007
|
if (isDisqualify)
|
|
@@ -1959,17 +2009,22 @@
|
|
|
1959
2009
|
}
|
|
1960
2010
|
else {
|
|
1961
2011
|
if (isDisqualify)
|
|
1962
|
-
return { isValid: false };
|
|
2012
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1963
2013
|
}
|
|
1964
2014
|
}
|
|
1965
2015
|
if (conditions?.spendCurrency) {
|
|
1966
|
-
const
|
|
1967
|
-
const
|
|
2016
|
+
const baseAmount = conditions.spendCurrency.amount || 1;
|
|
2017
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
2018
|
+
const trackerValue = completionTrackers?.spendCurrency || 0;
|
|
2019
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
2020
|
+
if (shouldScale && baseAmount > 0) {
|
|
2021
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
2022
|
+
}
|
|
1968
2023
|
if (addDetails) {
|
|
1969
2024
|
conditionData.push({
|
|
1970
2025
|
isMet: !isDisqualify,
|
|
1971
2026
|
kind: 'spendCurrency',
|
|
1972
|
-
trackerAmount:
|
|
2027
|
+
trackerAmount: trackerValue,
|
|
1973
2028
|
text: `Spend ${scaledAmount} ${conditions.spendCurrency.name}`,
|
|
1974
2029
|
});
|
|
1975
2030
|
if (isDisqualify)
|
|
@@ -1977,17 +2032,22 @@
|
|
|
1977
2032
|
}
|
|
1978
2033
|
else {
|
|
1979
2034
|
if (isDisqualify)
|
|
1980
|
-
return { isValid: false };
|
|
2035
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1981
2036
|
}
|
|
1982
2037
|
}
|
|
1983
2038
|
if (conditions?.depositCurrency) {
|
|
1984
|
-
const
|
|
1985
|
-
const
|
|
2039
|
+
const baseAmount = conditions.depositCurrency.amount || 1;
|
|
2040
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
2041
|
+
const trackerValue = completionTrackers?.depositCurrency || 0;
|
|
2042
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
2043
|
+
if (shouldScale && baseAmount > 0) {
|
|
2044
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
2045
|
+
}
|
|
1986
2046
|
if (addDetails) {
|
|
1987
2047
|
conditionData.push({
|
|
1988
2048
|
isMet: !isDisqualify,
|
|
1989
2049
|
kind: 'depositCurrency',
|
|
1990
|
-
trackerAmount:
|
|
2050
|
+
trackerAmount: trackerValue,
|
|
1991
2051
|
text: `Deposit ${scaledAmount} ${conditions.depositCurrency.name}`,
|
|
1992
2052
|
});
|
|
1993
2053
|
if (isDisqualify)
|
|
@@ -1995,7 +2055,7 @@
|
|
|
1995
2055
|
}
|
|
1996
2056
|
else {
|
|
1997
2057
|
if (isDisqualify)
|
|
1998
|
-
return { isValid: false };
|
|
2058
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
1999
2059
|
}
|
|
2000
2060
|
}
|
|
2001
2061
|
if (conditions?.login) {
|
|
@@ -2012,7 +2072,7 @@
|
|
|
2012
2072
|
}
|
|
2013
2073
|
else {
|
|
2014
2074
|
if (!isMet)
|
|
2015
|
-
return { isValid: false };
|
|
2075
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2016
2076
|
}
|
|
2017
2077
|
}
|
|
2018
2078
|
if (conditions?.loginStreak) {
|
|
@@ -2032,7 +2092,7 @@
|
|
|
2032
2092
|
}
|
|
2033
2093
|
else {
|
|
2034
2094
|
if (isDisqualify)
|
|
2035
|
-
return { isValid: false };
|
|
2095
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2036
2096
|
}
|
|
2037
2097
|
}
|
|
2038
2098
|
if (conditions?.social) {
|
|
@@ -2054,6 +2114,17 @@
|
|
|
2054
2114
|
if (likes < minLikes || views < minViews || comments < minComments) {
|
|
2055
2115
|
isDisqualify = true;
|
|
2056
2116
|
}
|
|
2117
|
+
if (shouldScale && mode === 'accumulate' && hasContent) {
|
|
2118
|
+
const baseLikes = cSocial?.minLikes || 0;
|
|
2119
|
+
const baseViews = cSocial?.minViews || 0;
|
|
2120
|
+
const baseComments = cSocial?.minComments || 0;
|
|
2121
|
+
if (baseLikes > 0)
|
|
2122
|
+
updateMax(Math.floor(likes / baseLikes));
|
|
2123
|
+
if (baseViews > 0)
|
|
2124
|
+
updateMax(Math.floor(views / baseViews));
|
|
2125
|
+
if (baseComments > 0)
|
|
2126
|
+
updateMax(Math.floor(comments / baseComments));
|
|
2127
|
+
}
|
|
2057
2128
|
if (addDetails) {
|
|
2058
2129
|
const platformMap = {
|
|
2059
2130
|
tiktok: 'TikTok',
|
|
@@ -2125,14 +2196,18 @@
|
|
|
2125
2196
|
}
|
|
2126
2197
|
else {
|
|
2127
2198
|
if (isDisqualify)
|
|
2128
|
-
return { isValid: false };
|
|
2199
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2129
2200
|
}
|
|
2130
2201
|
}
|
|
2131
2202
|
// Linked completions - wait for N linked entities to complete
|
|
2132
2203
|
if (conditions?.linkedCompletions?.min) {
|
|
2204
|
+
const baseMin = conditions.linkedCompletions.min;
|
|
2133
2205
|
const currentCount = completionTrackers?.linkedCompletions || 0;
|
|
2134
|
-
const scaledMin =
|
|
2206
|
+
const scaledMin = baseMin * claimMultiplier;
|
|
2135
2207
|
const isDisqualify = currentCount < scaledMin;
|
|
2208
|
+
if (shouldScale && baseMin > 0) {
|
|
2209
|
+
updateMax(Math.floor(currentCount / baseMin));
|
|
2210
|
+
}
|
|
2136
2211
|
if (addDetails) {
|
|
2137
2212
|
conditionData.push({
|
|
2138
2213
|
isMet: !isDisqualify,
|
|
@@ -2145,7 +2220,7 @@
|
|
|
2145
2220
|
}
|
|
2146
2221
|
else {
|
|
2147
2222
|
if (isDisqualify)
|
|
2148
|
-
return { isValid: false };
|
|
2223
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2149
2224
|
}
|
|
2150
2225
|
}
|
|
2151
2226
|
if (conditions?.dynamicTracker?.conditions?.length) {
|
|
@@ -2155,6 +2230,13 @@
|
|
|
2155
2230
|
...conditions.dynamicTracker,
|
|
2156
2231
|
conditions: resolvedConditions,
|
|
2157
2232
|
}, claimMultiplier);
|
|
2233
|
+
if (shouldScale) {
|
|
2234
|
+
const dynamicMax = getMaxClaimsForDynamicGroup(completionTrackers?.dynamicTracker || {}, {
|
|
2235
|
+
...conditions.dynamicTracker,
|
|
2236
|
+
conditions: resolvedConditions,
|
|
2237
|
+
}, playerOffer.claimedCount || 0);
|
|
2238
|
+
updateMax(dynamicMax);
|
|
2239
|
+
}
|
|
2158
2240
|
if (addDetails) {
|
|
2159
2241
|
conditionData.push({
|
|
2160
2242
|
isMet: dynamicResult,
|
|
@@ -2166,7 +2248,7 @@
|
|
|
2166
2248
|
}
|
|
2167
2249
|
else {
|
|
2168
2250
|
if (!dynamicResult)
|
|
2169
|
-
return { isValid: false };
|
|
2251
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2170
2252
|
}
|
|
2171
2253
|
}
|
|
2172
2254
|
const r = meetsBaseConditions({
|
|
@@ -2177,9 +2259,18 @@
|
|
|
2177
2259
|
});
|
|
2178
2260
|
isValid = isValid && r.isValid;
|
|
2179
2261
|
conditionData.push(...(r.conditionData || []));
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2262
|
+
if (maxClaimCount && maxClaimCount > 0) {
|
|
2263
|
+
updateMax(maxClaimCount);
|
|
2264
|
+
}
|
|
2265
|
+
const claimedCount = playerOffer.claimedCount || 0;
|
|
2266
|
+
let availableClaimsNow = !isValid
|
|
2267
|
+
? 0
|
|
2268
|
+
: maxTotalClaimsFromScaling === Infinity
|
|
2269
|
+
? -1
|
|
2270
|
+
: Math.max(0, maxTotalClaimsFromScaling - claimedCount);
|
|
2271
|
+
return { isValid, conditionData, availableClaimsNow };
|
|
2272
|
+
}
|
|
2273
|
+
return { isValid: true, conditionData: [], availableClaimsNow: -1 };
|
|
2183
2274
|
};
|
|
2184
2275
|
/**
|
|
2185
2276
|
* Checks if completion conditions were met before a specific expiry time.
|
|
@@ -2344,26 +2435,30 @@
|
|
|
2344
2435
|
}
|
|
2345
2436
|
}
|
|
2346
2437
|
const compareTo = isNumber ? Number(cond.compareTo) : String(cond.compareTo);
|
|
2347
|
-
switch (cond.operator) {
|
|
2348
|
-
case '==':
|
|
2349
|
-
return val === compareTo;
|
|
2350
|
-
case '!=':
|
|
2351
|
-
return val !== compareTo;
|
|
2352
|
-
}
|
|
2353
2438
|
if (isNumber && typeof compareTo === 'number') {
|
|
2439
|
+
const skipMultiplier = cond.operator === '==' || cond.operator === '!=';
|
|
2440
|
+
const scaledCompareTo = skipMultiplier ? compareTo : compareTo * claimMultiplier;
|
|
2354
2441
|
switch (cond.operator) {
|
|
2442
|
+
case '==':
|
|
2443
|
+
return val === scaledCompareTo;
|
|
2444
|
+
case '!=':
|
|
2445
|
+
return val !== scaledCompareTo;
|
|
2355
2446
|
case '>':
|
|
2356
|
-
return val >
|
|
2447
|
+
return val > scaledCompareTo;
|
|
2357
2448
|
case '>=':
|
|
2358
|
-
return val >=
|
|
2449
|
+
return val >= scaledCompareTo;
|
|
2359
2450
|
case '<':
|
|
2360
|
-
return val <
|
|
2451
|
+
return val < scaledCompareTo;
|
|
2361
2452
|
case '<=':
|
|
2362
|
-
return val <=
|
|
2453
|
+
return val <= scaledCompareTo;
|
|
2363
2454
|
}
|
|
2364
2455
|
}
|
|
2365
2456
|
else if (!isNumber && typeof compareTo === 'string') {
|
|
2366
2457
|
switch (cond.operator) {
|
|
2458
|
+
case '==':
|
|
2459
|
+
return val === compareTo;
|
|
2460
|
+
case '!=':
|
|
2461
|
+
return val !== compareTo;
|
|
2367
2462
|
case 'has':
|
|
2368
2463
|
return val.includes(compareTo);
|
|
2369
2464
|
case 'not_has':
|
|
@@ -2372,6 +2467,98 @@
|
|
|
2372
2467
|
}
|
|
2373
2468
|
return false;
|
|
2374
2469
|
}
|
|
2470
|
+
/**
|
|
2471
|
+
* Calculates the maximum number of claims supported by a single dynamic condition.
|
|
2472
|
+
*/
|
|
2473
|
+
function getMaxClaimsForDynamicCondition(dynamicObj, cond) {
|
|
2474
|
+
if (!dynamicObj)
|
|
2475
|
+
return 0;
|
|
2476
|
+
const val = dynamicObj[cond.key];
|
|
2477
|
+
if (val === undefined)
|
|
2478
|
+
return 0;
|
|
2479
|
+
if (typeof val === 'number') {
|
|
2480
|
+
const base = Number(cond.compareTo);
|
|
2481
|
+
if (isNaN(base)) {
|
|
2482
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2483
|
+
}
|
|
2484
|
+
switch (cond.operator) {
|
|
2485
|
+
case '>=':
|
|
2486
|
+
if (base === 0)
|
|
2487
|
+
return val >= 0 ? Infinity : 0;
|
|
2488
|
+
if (base < 0)
|
|
2489
|
+
return val >= base ? Infinity : 0;
|
|
2490
|
+
return Math.max(0, Math.floor(val / base));
|
|
2491
|
+
case '>':
|
|
2492
|
+
if (base === 0)
|
|
2493
|
+
return val > 0 ? Infinity : 0;
|
|
2494
|
+
if (base < 0)
|
|
2495
|
+
return val > base ? Infinity : 0;
|
|
2496
|
+
if (val <= 0)
|
|
2497
|
+
return 0;
|
|
2498
|
+
return Math.max(0, Math.ceil(val / base) - 1);
|
|
2499
|
+
case '==':
|
|
2500
|
+
return val === base ? Infinity : 0;
|
|
2501
|
+
case '!=':
|
|
2502
|
+
return val !== base ? Infinity : 0;
|
|
2503
|
+
case '<=':
|
|
2504
|
+
if (base === 0)
|
|
2505
|
+
return val <= 0 ? Infinity : 0;
|
|
2506
|
+
if (base > 0)
|
|
2507
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2508
|
+
if (val >= 0)
|
|
2509
|
+
return 0;
|
|
2510
|
+
return Math.max(0, Math.floor(val / base));
|
|
2511
|
+
case '<':
|
|
2512
|
+
if (base === 0)
|
|
2513
|
+
return val < 0 ? Infinity : 0;
|
|
2514
|
+
if (base > 0)
|
|
2515
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2516
|
+
if (val >= 0)
|
|
2517
|
+
return 0;
|
|
2518
|
+
return Math.max(0, Math.ceil(val / base) - 1);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
// we don't scale the rest, they are always true or always false
|
|
2522
|
+
return evaluateDynamicCondition(dynamicObj, cond, 1) ? Infinity : 0;
|
|
2523
|
+
}
|
|
2524
|
+
/**
|
|
2525
|
+
* Calculates the maximum number of claims supported by a group of dynamic conditions.
|
|
2526
|
+
*/
|
|
2527
|
+
function getMaxClaimsForDynamicGroup(dynamicObj, dynamicGroup, currentClaimCount = 0) {
|
|
2528
|
+
const { conditions, links } = dynamicGroup;
|
|
2529
|
+
if (!conditions || conditions.length === 0)
|
|
2530
|
+
return Infinity;
|
|
2531
|
+
// AND only
|
|
2532
|
+
if (!links || links.length === 0 || links.every((l) => l === 'AND')) {
|
|
2533
|
+
let minClaims = Infinity;
|
|
2534
|
+
for (const cond of conditions) {
|
|
2535
|
+
const max = getMaxClaimsForDynamicCondition(dynamicObj, cond);
|
|
2536
|
+
if (max === 0)
|
|
2537
|
+
return 0;
|
|
2538
|
+
minClaims = Math.min(minClaims, max);
|
|
2539
|
+
}
|
|
2540
|
+
return minClaims;
|
|
2541
|
+
}
|
|
2542
|
+
// OR only
|
|
2543
|
+
if (links.every((l) => l === 'OR')) {
|
|
2544
|
+
let maxClaims = 0;
|
|
2545
|
+
for (const cond of conditions) {
|
|
2546
|
+
const max = getMaxClaimsForDynamicCondition(dynamicObj, cond);
|
|
2547
|
+
if (max === Infinity)
|
|
2548
|
+
return Infinity;
|
|
2549
|
+
maxClaims = Math.max(maxClaims, max);
|
|
2550
|
+
}
|
|
2551
|
+
return maxClaims;
|
|
2552
|
+
}
|
|
2553
|
+
// mixed:
|
|
2554
|
+
const maxIterations = 100;
|
|
2555
|
+
for (let n = currentClaimCount + 1; n <= currentClaimCount + maxIterations; n++) {
|
|
2556
|
+
if (!meetsDynamicConditions(dynamicObj, dynamicGroup, n)) {
|
|
2557
|
+
return n - 1;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
return currentClaimCount + maxIterations;
|
|
2561
|
+
}
|
|
2375
2562
|
/**
|
|
2376
2563
|
* Evaluates a group of dynamic conditions with logical links (AND, OR, AND NOT).
|
|
2377
2564
|
* @param dynamicObj - The player's dynamic object with any key and string or number value.
|
|
@@ -2480,6 +2667,8 @@
|
|
|
2480
2667
|
exports.OfferwallClient = OfferwallClient;
|
|
2481
2668
|
exports.PlayerOfferStatuses = PlayerOfferStatuses;
|
|
2482
2669
|
exports.SSEConnection = SSEConnection;
|
|
2670
|
+
exports.getMaxClaimsForDynamicCondition = getMaxClaimsForDynamicCondition;
|
|
2671
|
+
exports.getMaxClaimsForDynamicGroup = getMaxClaimsForDynamicGroup;
|
|
2483
2672
|
exports.hasConditions = hasConditions;
|
|
2484
2673
|
exports.meetsBaseConditions = meetsBaseConditions;
|
|
2485
2674
|
exports.meetsClaimableConditions = meetsClaimableConditions;
|