@pixels-online/pixels-client-js-sdk 1.18.0 → 1.20.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 +257 -66
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +259 -65
- package/dist/index.js.map +1 -1
- package/dist/offerwall-sdk.umd.js +259 -65
- package/dist/offerwall-sdk.umd.js.map +1 -1
- package/dist/types/player.d.ts +98 -13
- package/dist/types/user.d.ts +62 -0
- package/dist/utils/blockchain_utils.d.ts +5 -0
- package/dist/utils/conditions.d.ts +25 -7
- package/dist/utils/dynamic.d.ts +2 -0
- package/dist/utils/template.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -628,25 +628,33 @@ class SSEConnection {
|
|
|
628
628
|
}
|
|
629
629
|
|
|
630
630
|
class OfferStore {
|
|
631
|
-
constructor(config) {
|
|
631
|
+
constructor(config, client) {
|
|
632
|
+
this.client = client;
|
|
632
633
|
this.offers = new Map();
|
|
633
|
-
this.
|
|
634
|
+
this.players = new Map();
|
|
634
635
|
this.logger = createLogger(config, 'OfferStore');
|
|
635
636
|
}
|
|
636
|
-
getPlayer() {
|
|
637
|
-
|
|
637
|
+
getPlayer(targetId = this.client.getSelfId()) {
|
|
638
|
+
if (!targetId)
|
|
639
|
+
return null;
|
|
640
|
+
return this.players.get(targetId) || null;
|
|
638
641
|
}
|
|
639
642
|
setPlayer(player) {
|
|
640
|
-
this.player
|
|
643
|
+
this.players.set(player.gameData.playerId, player);
|
|
641
644
|
this.logger.log('Updated player:', player);
|
|
642
645
|
}
|
|
643
646
|
/**
|
|
644
647
|
* Set all offers (replaces existing)
|
|
645
648
|
*/
|
|
646
|
-
setOffers(offers) {
|
|
647
|
-
this.
|
|
649
|
+
setOffers(offers, target) {
|
|
650
|
+
const targetPlayer = target || this.getPlayer();
|
|
651
|
+
if (!targetPlayer) {
|
|
652
|
+
this.logger.warn('No target player to set offers for');
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
this.offers.set(targetPlayer.gameData.playerId, new Map());
|
|
648
656
|
offers.forEach((offer) => {
|
|
649
|
-
this.offers.set(offer.instanceId, offer);
|
|
657
|
+
this.offers.get(targetPlayer.gameData.playerId).set(offer.instanceId, offer);
|
|
650
658
|
});
|
|
651
659
|
this.logger.log(`Set ${offers.length} offers`);
|
|
652
660
|
}
|
|
@@ -654,16 +662,23 @@ class OfferStore {
|
|
|
654
662
|
* Add or update a single offer
|
|
655
663
|
*/
|
|
656
664
|
upsertOffer(offer) {
|
|
657
|
-
|
|
658
|
-
|
|
665
|
+
let playerOffers = this.offers.get(offer.playerId);
|
|
666
|
+
if (!playerOffers) {
|
|
667
|
+
playerOffers = new Map();
|
|
668
|
+
this.offers.set(offer.playerId, playerOffers);
|
|
669
|
+
}
|
|
670
|
+
const previousOffer = playerOffers.get(offer.instanceId);
|
|
671
|
+
playerOffers.set(offer.instanceId, offer);
|
|
659
672
|
this.logger.log(`${previousOffer ? 'Updated' : 'Added'} offer:`, offer.instanceId);
|
|
660
673
|
return previousOffer;
|
|
661
674
|
}
|
|
662
675
|
/**
|
|
663
676
|
* Remove an offer
|
|
664
677
|
*/
|
|
665
|
-
removeOffer(offerId) {
|
|
666
|
-
|
|
678
|
+
removeOffer(offerId, targetId = this.client.getSelfId()) {
|
|
679
|
+
if (!targetId)
|
|
680
|
+
return false;
|
|
681
|
+
const removed = this.offers.get(targetId)?.delete(offerId) || false;
|
|
667
682
|
if (removed) {
|
|
668
683
|
this.logger.log(`Removed offer:`, offerId);
|
|
669
684
|
}
|
|
@@ -672,26 +687,30 @@ class OfferStore {
|
|
|
672
687
|
/**
|
|
673
688
|
* Get a single offer
|
|
674
689
|
*/
|
|
675
|
-
getOffer(offerId) {
|
|
676
|
-
|
|
690
|
+
getOffer(offerId, targetId = this.client.getSelfId()) {
|
|
691
|
+
if (!targetId)
|
|
692
|
+
return undefined;
|
|
693
|
+
return this.offers.get(targetId)?.get(offerId);
|
|
677
694
|
}
|
|
678
695
|
/**
|
|
679
696
|
* Get all offers
|
|
680
697
|
*/
|
|
681
|
-
getAllOffers() {
|
|
682
|
-
|
|
698
|
+
getAllOffers(targetId = this.client.getSelfId()) {
|
|
699
|
+
if (!targetId)
|
|
700
|
+
return [];
|
|
701
|
+
return Array.from(this.offers.get(targetId)?.values() || []);
|
|
683
702
|
}
|
|
684
703
|
/**
|
|
685
704
|
* Get offers filtered by status
|
|
686
705
|
*/
|
|
687
|
-
getOffersByStatus(status) {
|
|
688
|
-
return this.getAllOffers().filter((offer) => offer.status === status);
|
|
706
|
+
getOffersByStatus(status, targetId = this.client.getSelfId()) {
|
|
707
|
+
return this.getAllOffers(targetId).filter((offer) => offer.status === status);
|
|
689
708
|
}
|
|
690
709
|
/**
|
|
691
710
|
* Get active offers (not expired, not claimed)
|
|
692
711
|
*/
|
|
693
|
-
getActiveOffers() {
|
|
694
|
-
return this.getAllOffers().filter((offer) => {
|
|
712
|
+
getActiveOffers(targetId = this.client.getSelfId()) {
|
|
713
|
+
return this.getAllOffers(targetId).filter((offer) => {
|
|
695
714
|
if (!offer.status)
|
|
696
715
|
return false; // Must have a status
|
|
697
716
|
return (offer.status === 'surfaced' ||
|
|
@@ -702,14 +721,14 @@ class OfferStore {
|
|
|
702
721
|
/**
|
|
703
722
|
* Get claimable offers
|
|
704
723
|
*/
|
|
705
|
-
getClaimableOffers() {
|
|
706
|
-
return this.getOffersByStatus('claimable');
|
|
724
|
+
getClaimableOffers(targetId = this.client.getSelfId()) {
|
|
725
|
+
return this.getOffersByStatus('claimable', targetId);
|
|
707
726
|
}
|
|
708
727
|
/**
|
|
709
728
|
* Check if an offer has expired
|
|
710
729
|
*/
|
|
711
|
-
isOfferExpired(offerId) {
|
|
712
|
-
const offer = this.getOffer(offerId);
|
|
730
|
+
isOfferExpired(offerId, targetId = this.client.getSelfId()) {
|
|
731
|
+
const offer = this.getOffer(offerId, targetId);
|
|
713
732
|
if (!offer)
|
|
714
733
|
return true;
|
|
715
734
|
// Check status
|
|
@@ -722,17 +741,29 @@ class OfferStore {
|
|
|
722
741
|
return false;
|
|
723
742
|
}
|
|
724
743
|
/**
|
|
725
|
-
* Clear all offers
|
|
744
|
+
* Clear all offers for a specific player
|
|
745
|
+
*/
|
|
746
|
+
clear(targetId = this.client.getSelfId()) {
|
|
747
|
+
if (!targetId)
|
|
748
|
+
return;
|
|
749
|
+
this.offers.set(targetId, new Map());
|
|
750
|
+
this.logger.log('Cleared all offers for player:', targetId);
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Clear all offers for all players
|
|
726
754
|
*/
|
|
727
|
-
|
|
755
|
+
clearAll() {
|
|
728
756
|
this.offers.clear();
|
|
729
|
-
this.logger.log('Cleared all offers');
|
|
757
|
+
this.logger.log('Cleared all offers for all players');
|
|
730
758
|
}
|
|
731
759
|
/**
|
|
732
|
-
* Get offer count
|
|
760
|
+
* Get offer count (for self player)
|
|
733
761
|
*/
|
|
734
762
|
get size() {
|
|
735
|
-
|
|
763
|
+
const selfId = this.client.getSelfId();
|
|
764
|
+
if (!selfId)
|
|
765
|
+
return 0;
|
|
766
|
+
return this.offers.get(selfId)?.size || 0;
|
|
736
767
|
}
|
|
737
768
|
}
|
|
738
769
|
|
|
@@ -835,7 +866,9 @@ class AssetHelper {
|
|
|
835
866
|
return null;
|
|
836
867
|
}
|
|
837
868
|
setCurrencyAssetContents(currencies) {
|
|
838
|
-
|
|
869
|
+
Object.keys(currencies).forEach((key) => {
|
|
870
|
+
this.currencies[key] = currencies[key];
|
|
871
|
+
});
|
|
839
872
|
}
|
|
840
873
|
resolveReward(reward) {
|
|
841
874
|
if (reward.kind === 'loyalty_currency' && reward.rewardId) {
|
|
@@ -891,6 +924,7 @@ class OfferwallClient {
|
|
|
891
924
|
constructor(config) {
|
|
892
925
|
this.isInitializing = false;
|
|
893
926
|
this.pendingStackedToken = null;
|
|
927
|
+
this.selfId = null;
|
|
894
928
|
this.config = {
|
|
895
929
|
autoConnect: config.autoConnect ?? false,
|
|
896
930
|
reconnect: config.reconnect ?? true,
|
|
@@ -903,7 +937,7 @@ class OfferwallClient {
|
|
|
903
937
|
this.hooks = this.config.hooks || {};
|
|
904
938
|
this.logger = createLogger(this.config, 'OfferwallClient');
|
|
905
939
|
this.eventEmitter = new EventEmitter(this.config);
|
|
906
|
-
this.offerStore = new OfferStore(this.config);
|
|
940
|
+
this.offerStore = new OfferStore(this.config, this);
|
|
907
941
|
this.tokenManager = new TokenManager(this.config);
|
|
908
942
|
this.assetHelper = new AssetHelper(this.config);
|
|
909
943
|
this.sseConnection = new SSEConnection(this.config, this.eventEmitter, this.tokenManager);
|
|
@@ -944,6 +978,9 @@ class OfferwallClient {
|
|
|
944
978
|
get assets() {
|
|
945
979
|
return this.assetHelper;
|
|
946
980
|
}
|
|
981
|
+
getSelfId() {
|
|
982
|
+
return this.selfId;
|
|
983
|
+
}
|
|
947
984
|
/**
|
|
948
985
|
* Initialize the offerwall client and connect
|
|
949
986
|
*/
|
|
@@ -1006,8 +1043,9 @@ class OfferwallClient {
|
|
|
1006
1043
|
if (this.sseConnection) {
|
|
1007
1044
|
this.sseConnection.disconnect();
|
|
1008
1045
|
}
|
|
1009
|
-
this.offerStore.
|
|
1046
|
+
this.offerStore.clearAll();
|
|
1010
1047
|
this.tokenManager.clearToken();
|
|
1048
|
+
this.selfId = null;
|
|
1011
1049
|
if (this.hooks.afterDisconnect) {
|
|
1012
1050
|
await this.hooks.afterDisconnect();
|
|
1013
1051
|
}
|
|
@@ -1015,8 +1053,8 @@ class OfferwallClient {
|
|
|
1015
1053
|
/**
|
|
1016
1054
|
* Claim rewards for an offer
|
|
1017
1055
|
*/
|
|
1018
|
-
async claimReward(instanceId) {
|
|
1019
|
-
const offer = this.offerStore.getOffer(instanceId);
|
|
1056
|
+
async claimReward(instanceId, targetId = this.getSelfId()) {
|
|
1057
|
+
const offer = this.offerStore.getOffer(instanceId, targetId);
|
|
1020
1058
|
if (!offer) {
|
|
1021
1059
|
throw new Error(`Offer ${instanceId} not found`);
|
|
1022
1060
|
}
|
|
@@ -1031,7 +1069,7 @@ class OfferwallClient {
|
|
|
1031
1069
|
}
|
|
1032
1070
|
}
|
|
1033
1071
|
try {
|
|
1034
|
-
const response = await this.claimOfferAPI(instanceId);
|
|
1072
|
+
const response = await this.claimOfferAPI(instanceId, targetId);
|
|
1035
1073
|
const updatedOffer = { ...offer, status: 'claimed' };
|
|
1036
1074
|
this.offerStore.upsertOffer(updatedOffer);
|
|
1037
1075
|
this.eventEmitter.emit(OfferEvent.OFFER_CLAIMED, {
|
|
@@ -1087,7 +1125,7 @@ class OfferwallClient {
|
|
|
1087
1125
|
});
|
|
1088
1126
|
*/
|
|
1089
1127
|
this.eventEmitter.on(OfferEvent.OFFER_SURFACED, ({ offer }) => {
|
|
1090
|
-
this.offerStore.upsertOffer(offer);
|
|
1128
|
+
this.offerStore.upsertOffer(offer); // should always be selfId
|
|
1091
1129
|
this.logger.log(`Surfaced offer: ${offer.instanceId}`);
|
|
1092
1130
|
});
|
|
1093
1131
|
}
|
|
@@ -1117,34 +1155,40 @@ class OfferwallClient {
|
|
|
1117
1155
|
}
|
|
1118
1156
|
return response.json();
|
|
1119
1157
|
}
|
|
1120
|
-
async claimOfferAPI(instanceId) {
|
|
1158
|
+
async claimOfferAPI(instanceId, targetId = null) {
|
|
1121
1159
|
return this.postWithAuth('/v1/client/reward/claim', {
|
|
1122
1160
|
instanceId,
|
|
1123
1161
|
kind: 'offer',
|
|
1162
|
+
targetId: targetId || undefined,
|
|
1124
1163
|
});
|
|
1125
1164
|
}
|
|
1126
|
-
getPlayer() {
|
|
1127
|
-
return this.offerStore.getPlayer();
|
|
1165
|
+
getPlayer(targetId = this.getSelfId()) {
|
|
1166
|
+
return this.offerStore.getPlayer(targetId);
|
|
1128
1167
|
}
|
|
1129
|
-
getOffers() {
|
|
1130
|
-
return this.offerStore.getAllOffers();
|
|
1168
|
+
getOffers(targetId = this.getSelfId()) {
|
|
1169
|
+
return this.offerStore.getAllOffers(targetId);
|
|
1131
1170
|
}
|
|
1132
|
-
async refreshOffersAndPlayer() {
|
|
1171
|
+
async refreshOffersAndPlayer(targetId = null) {
|
|
1133
1172
|
try {
|
|
1134
|
-
const { offers, player } = await this.getOffersAndPlayer();
|
|
1135
|
-
|
|
1173
|
+
const { offers, player } = await this.getOffersAndPlayer(targetId);
|
|
1174
|
+
if (targetId == null) {
|
|
1175
|
+
this.selfId = player.gameData.playerId;
|
|
1176
|
+
}
|
|
1136
1177
|
this.offerStore.setPlayer(player);
|
|
1178
|
+
this.offerStore.setOffers(offers, player);
|
|
1137
1179
|
this.eventEmitter.emit(OfferEvent.REFRESH, { offers, player: player });
|
|
1138
1180
|
this.logger.log('Refreshed offers and player snapshot');
|
|
1181
|
+
return offers;
|
|
1139
1182
|
}
|
|
1140
1183
|
catch (error) {
|
|
1141
1184
|
this.handleError(error, 'refreshOffersAndPlayer');
|
|
1142
1185
|
throw error;
|
|
1143
1186
|
}
|
|
1144
1187
|
}
|
|
1145
|
-
async getOffersAndPlayer() {
|
|
1188
|
+
async getOffersAndPlayer(targetId = null) {
|
|
1146
1189
|
const data = await this.postWithAuth('/v1/client/player/campaigns', {
|
|
1147
1190
|
viewingCampaigns: true,
|
|
1191
|
+
targetId: targetId || undefined,
|
|
1148
1192
|
});
|
|
1149
1193
|
if (!data.offers || !Array.isArray(data.offers)) {
|
|
1150
1194
|
throw new Error('No offers returned from offers endpoint');
|
|
@@ -1277,6 +1321,8 @@ class OfferwallClient {
|
|
|
1277
1321
|
}
|
|
1278
1322
|
}
|
|
1279
1323
|
|
|
1324
|
+
const DEFAULT_ENTITY_KIND = '_default';
|
|
1325
|
+
|
|
1280
1326
|
const keyPattern = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
1281
1327
|
/**
|
|
1282
1328
|
* This replaces {keyName} keys from the template with corresponding values from the dynamic object.
|
|
@@ -1314,11 +1360,25 @@ function replaceDynamicConditionKeys(conditions, trackers) {
|
|
|
1314
1360
|
}));
|
|
1315
1361
|
}
|
|
1316
1362
|
|
|
1363
|
+
const dynamicTrackerToPrimitive = (dynaTrack) => {
|
|
1364
|
+
const primitive = {};
|
|
1365
|
+
for (const key in dynaTrack) {
|
|
1366
|
+
primitive[key] = dynaTrack[key].value || 0;
|
|
1367
|
+
}
|
|
1368
|
+
return primitive;
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1371
|
+
const addressNetworkId = (contractAddress, network) => {
|
|
1372
|
+
return `${contractAddress.toLowerCase()}:${network.toUpperCase()}`;
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1317
1375
|
const meetsBaseConditions = ({ conditions, playerSnap, addDetails,
|
|
1318
1376
|
/** this exists if calling meetsBaseConditions from meetsCompletionConditions. but surfacing
|
|
1319
1377
|
* check doesn't use this since we don't have a playerOffer at surfacing time
|
|
1320
1378
|
*/
|
|
1321
|
-
playerOffer,
|
|
1379
|
+
playerOffer,
|
|
1380
|
+
/** Additional data like fetched token balances that isn't part of playerSnap */
|
|
1381
|
+
additionalData, }) => {
|
|
1322
1382
|
const conditionData = [];
|
|
1323
1383
|
let isValid = true;
|
|
1324
1384
|
if (conditions?.minDaysInGame) {
|
|
@@ -1646,7 +1706,8 @@ playerOffer, }) => {
|
|
|
1646
1706
|
// Validate link count conditions
|
|
1647
1707
|
if (conditions?.links && 'entityLinks' in playerSnap) {
|
|
1648
1708
|
for (const [linkType, constraint] of Object.entries(conditions.links)) {
|
|
1649
|
-
|
|
1709
|
+
// linkType should always exist. and be default is none was specified
|
|
1710
|
+
const linkCount = playerSnap.entityLinks?.filter((link) => (link.kind || DEFAULT_ENTITY_KIND) === linkType).length || 0;
|
|
1650
1711
|
if (constraint.min !== undefined) {
|
|
1651
1712
|
const isDisqualify = linkCount < constraint.min;
|
|
1652
1713
|
if (addDetails) {
|
|
@@ -1733,16 +1794,60 @@ playerOffer, }) => {
|
|
|
1733
1794
|
return { isValid: false };
|
|
1734
1795
|
}
|
|
1735
1796
|
}
|
|
1797
|
+
// Evaluate token balance conditions
|
|
1798
|
+
for (const tokenCond of conditions?.tokenBalances || []) {
|
|
1799
|
+
const contracts = tokenCond.contracts || [];
|
|
1800
|
+
let totalBalance = 0;
|
|
1801
|
+
const fetchedBalances = aggregateTokenBalances(additionalData);
|
|
1802
|
+
for (const contract of contracts) {
|
|
1803
|
+
const balanceKey = addressNetworkId(contract.contractAddress, contract.network);
|
|
1804
|
+
totalBalance += fetchedBalances[balanceKey] || 0;
|
|
1805
|
+
}
|
|
1806
|
+
if (tokenCond.min !== undefined) {
|
|
1807
|
+
const isDisqualify = totalBalance < tokenCond.min;
|
|
1808
|
+
if (addDetails) {
|
|
1809
|
+
conditionData.push({
|
|
1810
|
+
isMet: !isDisqualify,
|
|
1811
|
+
kind: 'tokenBalances',
|
|
1812
|
+
trackerAmount: totalBalance,
|
|
1813
|
+
text: `Have at least ${tokenCond.min} ${tokenCond.name || 'tokens'}`,
|
|
1814
|
+
});
|
|
1815
|
+
if (isDisqualify)
|
|
1816
|
+
isValid = false;
|
|
1817
|
+
}
|
|
1818
|
+
else {
|
|
1819
|
+
if (isDisqualify)
|
|
1820
|
+
return { isValid: false };
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
if (tokenCond.max !== undefined) {
|
|
1824
|
+
const isDisqualify = totalBalance > tokenCond.max;
|
|
1825
|
+
if (addDetails) {
|
|
1826
|
+
conditionData.push({
|
|
1827
|
+
isMet: !isDisqualify,
|
|
1828
|
+
kind: 'tokenBalances',
|
|
1829
|
+
trackerAmount: totalBalance,
|
|
1830
|
+
text: `Have at most ${tokenCond.max} ${tokenCond.name || 'tokens'}`,
|
|
1831
|
+
});
|
|
1832
|
+
if (isDisqualify)
|
|
1833
|
+
isValid = false;
|
|
1834
|
+
}
|
|
1835
|
+
else {
|
|
1836
|
+
if (isDisqualify)
|
|
1837
|
+
return { isValid: false };
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1736
1841
|
return { isValid, conditionData: addDetails ? conditionData : undefined };
|
|
1737
1842
|
};
|
|
1738
|
-
const meetsSurfacingConditions = ({ surfacingConditions, playerSnap, context, playerOffers, }) => {
|
|
1843
|
+
const meetsSurfacingConditions = ({ surfacingConditions, playerSnap, context, playerOffers, additionalData, }) => {
|
|
1739
1844
|
if (surfacingConditions?.contexts?.length &&
|
|
1740
1845
|
!surfacingConditions.contexts?.includes(context || '')) {
|
|
1741
1846
|
// context is not in the list of surfacing contexts, so we don't want to surface this offer
|
|
1742
1847
|
return { isValid: false };
|
|
1743
1848
|
}
|
|
1744
1849
|
if (surfacingConditions?.targetEntityTypes?.length) {
|
|
1745
|
-
const playerTarget = playerSnap.entityKind ||
|
|
1850
|
+
const playerTarget = playerSnap.entityKind || DEFAULT_ENTITY_KIND;
|
|
1746
1851
|
// check if entity type is allowed
|
|
1747
1852
|
if (!surfacingConditions.targetEntityTypes.includes(playerTarget)) {
|
|
1748
1853
|
return { isValid: false };
|
|
@@ -1823,7 +1928,7 @@ const meetsSurfacingConditions = ({ surfacingConditions, playerSnap, context, pl
|
|
|
1823
1928
|
}
|
|
1824
1929
|
}
|
|
1825
1930
|
}
|
|
1826
|
-
return meetsBaseConditions({ conditions, playerSnap });
|
|
1931
|
+
return meetsBaseConditions({ conditions, playerSnap, additionalData });
|
|
1827
1932
|
};
|
|
1828
1933
|
const hasConditions = (conditions) => {
|
|
1829
1934
|
if (!conditions)
|
|
@@ -1881,6 +1986,8 @@ const hasConditions = (conditions) => {
|
|
|
1881
1986
|
return true;
|
|
1882
1987
|
if (surCond.networkRestrictions?.length)
|
|
1883
1988
|
return true;
|
|
1989
|
+
if (surCond.linkedEntityOffers?.offer_id)
|
|
1990
|
+
return true;
|
|
1884
1991
|
const compCond = conditions;
|
|
1885
1992
|
if (compCond.context)
|
|
1886
1993
|
return true;
|
|
@@ -1900,23 +2007,47 @@ const hasConditions = (conditions) => {
|
|
|
1900
2007
|
return true;
|
|
1901
2008
|
if (compCond.dynamicTracker?.conditions?.length)
|
|
1902
2009
|
return true;
|
|
2010
|
+
if (conditions.tokenBalances?.length)
|
|
2011
|
+
return true;
|
|
2012
|
+
if (Object.keys(compCond.contractInteractions || {}).length > 0)
|
|
2013
|
+
return true;
|
|
1903
2014
|
return false;
|
|
1904
2015
|
};
|
|
1905
|
-
const
|
|
2016
|
+
const meetsLinkedEntityOffersCondition = ({ linkedEntityOffers, matchingLinks, linkedPOfferMap, }) => {
|
|
2017
|
+
if (!linkedPOfferMap)
|
|
2018
|
+
return { isValid: false };
|
|
2019
|
+
const linkedPlayerOffer_ids = [];
|
|
2020
|
+
for (const link of matchingLinks) {
|
|
2021
|
+
const key = `${link.playerId}:${linkedEntityOffers.offer_id}`;
|
|
2022
|
+
const po = linkedPOfferMap.get(key);
|
|
2023
|
+
if (po) {
|
|
2024
|
+
linkedPlayerOffer_ids.push(po._id.toString());
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (linkedPlayerOffer_ids.length > 0) {
|
|
2028
|
+
return { isValid: true, linkedPlayerOffer_ids };
|
|
2029
|
+
}
|
|
2030
|
+
return { isValid: false };
|
|
2031
|
+
};
|
|
2032
|
+
const offerMeetsCompletionConditions = (offer, snapshot, additionalData) => {
|
|
1906
2033
|
return meetsCompletionConditions({
|
|
1907
2034
|
completionConditions: offer.completionConditions || {},
|
|
1908
2035
|
completionTrackers: offer.completionTrackers,
|
|
1909
2036
|
playerSnap: snapshot,
|
|
1910
2037
|
playerOffer: offer,
|
|
1911
2038
|
addDetails: true,
|
|
2039
|
+
maxClaimCount: offer.maxClaimCount,
|
|
2040
|
+
additionalData,
|
|
1912
2041
|
});
|
|
1913
2042
|
};
|
|
1914
|
-
const meetsCompletionConditions = ({ completionConditions, completionTrackers, playerSnap, playerOffer, addDetails = false, maxClaimCount, }) => {
|
|
2043
|
+
const meetsCompletionConditions = ({ completionConditions, completionTrackers, playerSnap, playerOffer, addDetails = false, maxClaimCount, additionalData, }) => {
|
|
1915
2044
|
if (completionConditions) {
|
|
1916
2045
|
const conditions = completionConditions;
|
|
1917
2046
|
// For multi-claim offers, scale cumulative requirements by (claimedCount + 1)
|
|
1918
2047
|
const shouldScale = maxClaimCount === -1 || (maxClaimCount && maxClaimCount > 1);
|
|
1919
|
-
const claimMultiplier = shouldScale
|
|
2048
|
+
const claimMultiplier = shouldScale
|
|
2049
|
+
? (playerOffer.trackers?.claimedCount || 0) + 1
|
|
2050
|
+
: 1;
|
|
1920
2051
|
const conditionData = [];
|
|
1921
2052
|
let isValid = true;
|
|
1922
2053
|
let maxTotalClaimsFromScaling = Infinity;
|
|
@@ -2047,12 +2178,14 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2047
2178
|
}
|
|
2048
2179
|
}
|
|
2049
2180
|
if (conditions?.social) {
|
|
2050
|
-
const
|
|
2181
|
+
const tSocialAccumulate = completionTrackers?.social;
|
|
2182
|
+
const tSocialAttach = completionTrackers?.social;
|
|
2051
2183
|
const cSocial = completionConditions.social;
|
|
2052
2184
|
const mode = cSocial?.mode || 'attach';
|
|
2185
|
+
const tSocial = mode === 'accumulate' ? tSocialAccumulate : tSocialAttach;
|
|
2053
2186
|
const hasContent = Boolean(mode === 'accumulate'
|
|
2054
|
-
?
|
|
2055
|
-
:
|
|
2187
|
+
? tSocialAccumulate?.matchCount > 0
|
|
2188
|
+
: tSocialAttach?.videoId);
|
|
2056
2189
|
// Only scale social metrics in accumulate mode (attach mode is single content)
|
|
2057
2190
|
const socialMultiplier = mode === 'accumulate' ? claimMultiplier : 1;
|
|
2058
2191
|
const minLikes = (cSocial?.minLikes || 0) * socialMultiplier;
|
|
@@ -2087,7 +2220,7 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2087
2220
|
.join(' | ');
|
|
2088
2221
|
const requiredWords = cSocial?.requiredWords ?? [];
|
|
2089
2222
|
if (mode === 'accumulate') {
|
|
2090
|
-
const matchCount =
|
|
2223
|
+
const matchCount = tSocialAccumulate?.matchCount || 0;
|
|
2091
2224
|
conditionData.push({
|
|
2092
2225
|
isMet: hasContent,
|
|
2093
2226
|
kind: 'social',
|
|
@@ -2100,7 +2233,7 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2100
2233
|
});
|
|
2101
2234
|
}
|
|
2102
2235
|
else {
|
|
2103
|
-
const title =
|
|
2236
|
+
const title = tSocialAttach?.title;
|
|
2104
2237
|
conditionData.push({
|
|
2105
2238
|
isMet: hasContent,
|
|
2106
2239
|
kind: 'social',
|
|
@@ -2177,22 +2310,22 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2177
2310
|
if (conditions?.dynamicTracker?.conditions?.length) {
|
|
2178
2311
|
const resolvedConditions = replaceDynamicConditionKeys(conditions.dynamicTracker.conditions, playerOffer?.trackers || {});
|
|
2179
2312
|
// now we have the game-defined conditions with {{}} keys populated. feed these conditions into evaluator
|
|
2180
|
-
const dynamicResult = meetsDynamicConditions(completionTrackers?.dynamicTracker, {
|
|
2313
|
+
const dynamicResult = meetsDynamicConditions(dynamicTrackerToPrimitive(completionTrackers?.dynamicTracker || {}), {
|
|
2181
2314
|
...conditions.dynamicTracker,
|
|
2182
2315
|
conditions: resolvedConditions,
|
|
2183
2316
|
}, claimMultiplier);
|
|
2184
2317
|
if (shouldScale) {
|
|
2185
|
-
const dynamicMax = getMaxClaimsForDynamicGroup(completionTrackers?.dynamicTracker || {}, {
|
|
2318
|
+
const dynamicMax = getMaxClaimsForDynamicGroup(dynamicTrackerToPrimitive(completionTrackers?.dynamicTracker || {}), {
|
|
2186
2319
|
...conditions.dynamicTracker,
|
|
2187
2320
|
conditions: resolvedConditions,
|
|
2188
|
-
}, playerOffer
|
|
2321
|
+
}, playerOffer?.trackers?.claimedCount || 0);
|
|
2189
2322
|
updateMax(dynamicMax);
|
|
2190
2323
|
}
|
|
2191
2324
|
if (addDetails) {
|
|
2192
2325
|
conditionData.push({
|
|
2193
2326
|
isMet: dynamicResult,
|
|
2194
|
-
kind: '
|
|
2195
|
-
text: renderTemplate(conditions.dynamicTracker.template, completionTrackers?.dynamicTracker) || 'Dynamic conditions',
|
|
2327
|
+
kind: 'dynamicTracker',
|
|
2328
|
+
text: renderTemplate(conditions.dynamicTracker.template, dynamicTrackerToPrimitive(completionTrackers?.dynamicTracker || {})) || 'Dynamic conditions',
|
|
2196
2329
|
});
|
|
2197
2330
|
if (!dynamicResult)
|
|
2198
2331
|
isValid = false;
|
|
@@ -2202,19 +2335,64 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
|
|
|
2202
2335
|
return { isValid: false, availableClaimsNow: 0 };
|
|
2203
2336
|
}
|
|
2204
2337
|
}
|
|
2338
|
+
// Evaluate contractInteractions completion trackers
|
|
2339
|
+
if (conditions?.contractInteractions) {
|
|
2340
|
+
for (const [conditionId, condition] of Object.entries(conditions.contractInteractions)) {
|
|
2341
|
+
const baseAmount = condition.amount || 0;
|
|
2342
|
+
const scaledAmount = baseAmount * claimMultiplier;
|
|
2343
|
+
const trackerValue = completionTrackers?.contractInteractions?.[conditionId] || 0;
|
|
2344
|
+
const isDisqualify = trackerValue < scaledAmount;
|
|
2345
|
+
if (shouldScale && baseAmount > 0) {
|
|
2346
|
+
updateMax(Math.floor(trackerValue / baseAmount));
|
|
2347
|
+
}
|
|
2348
|
+
if (addDetails) {
|
|
2349
|
+
let displayText;
|
|
2350
|
+
const eventType = condition.event;
|
|
2351
|
+
const name = condition.name || 'tokens';
|
|
2352
|
+
if (eventType === 'spend') {
|
|
2353
|
+
displayText = `Spend ${scaledAmount} ${name}`;
|
|
2354
|
+
}
|
|
2355
|
+
else if (eventType === 'earn') {
|
|
2356
|
+
displayText = `Earn ${scaledAmount} ${name}`;
|
|
2357
|
+
}
|
|
2358
|
+
else if (eventType === 'gain') {
|
|
2359
|
+
displayText = `Gain ${scaledAmount} ${name}`;
|
|
2360
|
+
}
|
|
2361
|
+
else if (eventType === 'lose') {
|
|
2362
|
+
displayText = `Lose ${scaledAmount} ${name}`;
|
|
2363
|
+
}
|
|
2364
|
+
else {
|
|
2365
|
+
displayText = `${name}: ${scaledAmount}`;
|
|
2366
|
+
}
|
|
2367
|
+
conditionData.push({
|
|
2368
|
+
isMet: !isDisqualify,
|
|
2369
|
+
kind: 'contractInteractions',
|
|
2370
|
+
trackerAmount: trackerValue,
|
|
2371
|
+
text: displayText,
|
|
2372
|
+
});
|
|
2373
|
+
if (isDisqualify)
|
|
2374
|
+
isValid = false;
|
|
2375
|
+
}
|
|
2376
|
+
else {
|
|
2377
|
+
if (isDisqualify)
|
|
2378
|
+
return { isValid: false, availableClaimsNow: 0 };
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2205
2382
|
const r = meetsBaseConditions({
|
|
2206
2383
|
conditions,
|
|
2207
2384
|
playerSnap,
|
|
2208
2385
|
addDetails: true,
|
|
2209
2386
|
playerOffer,
|
|
2387
|
+
additionalData,
|
|
2210
2388
|
});
|
|
2211
2389
|
isValid = isValid && r.isValid;
|
|
2212
2390
|
conditionData.push(...(r.conditionData || []));
|
|
2213
2391
|
if (maxClaimCount && maxClaimCount > 0) {
|
|
2214
2392
|
updateMax(maxClaimCount);
|
|
2215
2393
|
}
|
|
2216
|
-
const claimedCount = playerOffer
|
|
2217
|
-
|
|
2394
|
+
const claimedCount = playerOffer?.trackers?.claimedCount || 0;
|
|
2395
|
+
const availableClaimsNow = !isValid
|
|
2218
2396
|
? 0
|
|
2219
2397
|
: maxTotalClaimsFromScaling === Infinity
|
|
2220
2398
|
? -1
|
|
@@ -2565,6 +2743,19 @@ function meetsClaimableConditions({ claimableConditions, playerOfferTrackers, cl
|
|
|
2565
2743
|
}
|
|
2566
2744
|
return { isValid: true };
|
|
2567
2745
|
}
|
|
2746
|
+
// returns contractAddress:network -> balance
|
|
2747
|
+
function aggregateTokenBalances(data) {
|
|
2748
|
+
const aggregatedBalances = {};
|
|
2749
|
+
for (const { balances } of data?.cryptoWallets || []) {
|
|
2750
|
+
for (const [key, balance] of Object.entries(balances)) {
|
|
2751
|
+
if (!aggregatedBalances[key]) {
|
|
2752
|
+
aggregatedBalances[key] = 0;
|
|
2753
|
+
}
|
|
2754
|
+
aggregatedBalances[key] += balance;
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
return aggregatedBalances;
|
|
2758
|
+
}
|
|
2568
2759
|
|
|
2569
2760
|
const offerListenerEvents = ['claim_offer'];
|
|
2570
2761
|
const PlayerOfferStatuses = [
|
|
@@ -2612,5 +2803,5 @@ const rewardSchema = {
|
|
|
2612
2803
|
image: String,
|
|
2613
2804
|
};
|
|
2614
2805
|
|
|
2615
|
-
export { AssetHelper, ConnectionState, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, getMaxClaimsForDynamicCondition, getMaxClaimsForDynamicGroup, hasConditions, meetsBaseConditions, meetsClaimableConditions, meetsCompletionConditions, meetsCompletionConditionsBeforeExpiry, meetsDynamicConditions, meetsSurfacingConditions, offerListenerEvents, offerMeetsCompletionConditions, rewardKinds, rewardSchema };
|
|
2806
|
+
export { AssetHelper, ConnectionState, DEFAULT_ENTITY_KIND, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, aggregateTokenBalances, getMaxClaimsForDynamicCondition, getMaxClaimsForDynamicGroup, hasConditions, meetsBaseConditions, meetsClaimableConditions, meetsCompletionConditions, meetsCompletionConditionsBeforeExpiry, meetsDynamicConditions, meetsLinkedEntityOffersCondition, meetsSurfacingConditions, offerListenerEvents, offerMeetsCompletionConditions, rewardKinds, rewardSchema };
|
|
2616
2807
|
//# sourceMappingURL=index.esm.js.map
|