@pixels-online/pixels-client-js-sdk 1.3.0 → 1.5.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/README.md CHANGED
@@ -68,7 +68,8 @@ client.on('offersUpdated', (offers) => {
68
68
 
69
69
  // Listen for player updates
70
70
  client.on('playerUpdated', (player) => {
71
- console.log('Player data updated:', player);
71
+ console.log('Player snapshot updated:', player.snapshot);
72
+ console.log('Player data updated:', player.data);
72
73
  updatePlayerStatsUI(player);
73
74
  });
74
75
  ```
@@ -85,6 +86,36 @@ try {
85
86
  }
86
87
  ```
87
88
 
89
+ ## 📊 Player Data Structure
90
+
91
+ The SDK provides player information through the `IClientPlayer` interface:
92
+
93
+ ```typescript
94
+ interface IClientPlayer {
95
+ snapshot: IPlayerSnapshot; // Core player data (levels, currencies, achievements, etc.)
96
+ data?: IPlayerData | null; // Additional game-specific data
97
+ }
98
+ ```
99
+
100
+ ### Accessing Player Information
101
+
102
+ ```typescript
103
+ // Get the current player
104
+ const player = client.getPlayer();
105
+
106
+ if (player) {
107
+ // Access core player data
108
+ console.log('Player ID:', player.snapshot.playerId);
109
+ console.log('Player level:', player.snapshot.levels?.combat?.level);
110
+ console.log('Currency balance:', player.snapshot.currencies?.gold?.balance);
111
+
112
+ // Access additional player data (if available)
113
+ if (player.data) {
114
+ console.log('Additional currencies:', player.data.currencies);
115
+ }
116
+ }
117
+ ```
118
+
88
119
  ## 🎯 Configuration Options
89
120
 
90
121
  ### OfferwallConfig
@@ -157,7 +188,8 @@ const client = new OfferwallClient({
157
188
  // Control which offers to show
158
189
  onOfferSurfaced: (offer) => {
159
190
  // Custom logic to determine if offer should be shown
160
- return player.level >= offer.minLevel;
191
+ const currentPlayer = client.getPlayer();
192
+ return currentPlayer?.snapshot.levels?.overall?.level >= offer.minLevel;
161
193
  },
162
194
 
163
195
  // Handle successful offer claims
@@ -234,22 +266,14 @@ Initialize the client and establish connection.
234
266
 
235
267
  Disconnect from the service.
236
268
 
237
- #### `getOffers(): IClientOffer[]`
238
-
239
- Get all current offers.
269
+ #### `refreshOffersAndPlayer(): { offers: IClientOffer[], player: IClientPlayer }`
240
270
 
241
- #### `getOffer(offerId: string): IClientOffer | null`
242
-
243
- Get a specific offer by ID.
271
+ Refresh and get all current offers.
244
272
 
245
273
  #### `claimOffer(offerId: string): Promise<ClaimResult>`
246
274
 
247
275
  Claim an offer and receive rewards.
248
276
 
249
- #### `getPlayer(): IClientPlayerSnapshot | null`
250
-
251
- Get current player data.
252
-
253
277
  #### `getConnectionState(): ConnectionState`
254
278
 
255
279
  Get current connection status.
@@ -260,7 +284,7 @@ Get current connection status.
260
284
  import { meetsConditions, AssetHelper } from '@pixels-online/pixels-client-js-sdk';
261
285
 
262
286
  // Check if player meets offer conditions
263
- const canClaim = meetsConditions(player, offer.surfacingConditions);
287
+ const canClaim = meetsConditions(player.snapshot, offer.surfacingConditions);
264
288
 
265
289
  // Asset helper utilities
266
290
  const assetHelper = new AssetHelper(assetResolver, fallbackImage);
@@ -302,7 +326,53 @@ The SDK supports multiple environments:
302
326
  - **`dev`** - Development environment
303
327
  - **Custom URL** - Provide your own endpoint
304
328
 
305
- ## 📋 Requirements
329
+ ## Migration Guide
330
+
331
+ ### v1.0.0+ Breaking Changes
332
+
333
+ **Player Data Structure Update**
334
+
335
+ The player data structure has been updated to provide better separation between core player data and additional game-specific data:
336
+
337
+ - **Old**: `IClientPlayerSnapshot` (flat structure)
338
+ - **New**: `IClientPlayer` (structured with `snapshot` and `data` properties)
339
+
340
+ **Migration Steps:**
341
+
342
+ ```typescript
343
+ // Before (v0.x)
344
+ const player = client.getPlayer(); // IClientPlayerSnapshot
345
+ const level = player.levels?.combat?.level;
346
+ const gold = player.currencies?.gold?.balance;
347
+
348
+ // After (v1.0+)
349
+ const player = client.getPlayer(); // IClientPlayer
350
+ const level = player.snapshot.levels?.combat?.level;
351
+ const gold = player.snapshot.currencies?.gold?.balance;
352
+
353
+ // Access additional data (new feature)
354
+ const additionalCurrencies = player.data?.currencies;
355
+ ```
356
+
357
+ **Event Handler Updates:**
358
+
359
+ ```typescript
360
+ // Before
361
+ client.on('playerUpdated', (playerSnapshot) => {
362
+ updateUI(playerSnapshot.currencies);
363
+ });
364
+
365
+ // After
366
+ client.on('playerUpdated', (player) => {
367
+ updateUI(player.snapshot.currencies);
368
+ // Also handle additional data if needed
369
+ if (player.data) {
370
+ handleAdditionalData(player.data);
371
+ }
372
+ });
373
+ ```
374
+
375
+ ## �📋 Requirements
306
376
 
307
377
  - Node.js 16+
308
378
  - TypeScript 4.5+ (if using TypeScript)
@@ -1,13 +1,13 @@
1
1
  import { OfferwallConfig } from '../types';
2
2
  import { IClientOffer, PlayerOfferStatus } from '../types/offer';
3
- import { IClientPlayerSnapshot } from '../types/player';
3
+ import { IClientPlayer } from '../types/player';
4
4
  export declare class OfferStore {
5
5
  private offers;
6
- private playerSnapshot;
6
+ private player;
7
7
  private logger;
8
8
  constructor(config: OfferwallConfig);
9
- getSnapshot(): IClientPlayerSnapshot | null;
10
- setSnapshot(snapshot: IClientPlayerSnapshot): void;
9
+ getPlayer(): IClientPlayer | null;
10
+ setPlayer(player: IClientPlayer): void;
11
11
  /**
12
12
  * Set all offers (replaces existing)
13
13
  */
@@ -1,9 +1,11 @@
1
1
  import { EventEmitter } from '../events/EventEmitter';
2
2
  import { OfferStore } from './OfferStore';
3
3
  import { AssetHelper } from '../utils/assets';
4
- import { OfferwallConfig } from '../types';
4
+ import { OfferwallConfig } from '../types/index';
5
+ import { IClientOffer } from '../types/offer';
5
6
  import { ConnectionState } from '../types/connection';
6
- export declare const mapEnvToBuildOnApiUrl: (env: "test" | "live" | (string & {})) => "https://api.pixels.xyz" | "https://api.sandbox.pixels.xyz" | "https://api.staging.pixels.xyz" | "https://api.preview.pixels.xyz" | "https://api.dev.pixels.xyz";
7
+ import { IClientPlayer } from '../types/player';
8
+ export declare const mapEnvToOfferClientUrl: (env: "test" | "live" | (string & {})) => "https://offers.pixels.xyz" | "https://offers.sandbox.pixels.xyz" | "https://offers.staging.pixels.xyz" | "https://offers.preview.pixels.xyz" | "https://offers.dev.pixels.xyz";
7
9
  export declare class OfferwallClient {
8
10
  private config;
9
11
  private endpoint;
@@ -58,9 +60,12 @@ export declare class OfferwallClient {
58
60
  */
59
61
  private postWithAuth;
60
62
  private claimOfferAPI;
61
- refreshOffersAndSnapshot(): Promise<void>;
62
- private getOffersAndSnapshot;
63
+ getPlayer(): IClientPlayer | null;
64
+ getOffers(): IClientOffer[];
65
+ refreshOffersAndPlayer(): Promise<void>;
66
+ private getOffersAndPlayer;
63
67
  getAuthLinkToken(): Promise<string>;
64
68
  getGameId(): string | null;
69
+ getDashboardRedirectUrl(): Promise<string | null>;
65
70
  private handleError;
66
71
  }
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from '../events/EventEmitter';
2
- import { OfferwallConfig } from '../types';
2
+ import { OfferwallConfig } from '../types/index';
3
3
  import { ConnectionState } from '../types/connection';
4
4
  import { TokenManager } from './TokenManager';
5
5
  export declare class SSEConnection {
package/dist/index.esm.js CHANGED
@@ -332,6 +332,24 @@ class CustomEventSource {
332
332
  }
333
333
  }
334
334
 
335
+ const mapEnvToBuildOnApiUrl = (env) => {
336
+ switch (env) {
337
+ case 'live':
338
+ return 'https://api.pixels.xyz';
339
+ case 'test':
340
+ return 'https://api.sandbox.pixels.xyz';
341
+ case 'staging':
342
+ return 'https://api.staging.pixels.xyz';
343
+ case 'preview':
344
+ return 'https://api.preview.pixels.xyz';
345
+ case 'dev':
346
+ case 'development':
347
+ return 'https://api.dev.pixels.xyz';
348
+ default:
349
+ return 'https://api.sandbox.pixels.xyz';
350
+ }
351
+ };
352
+
335
353
  class SSEConnection {
336
354
  constructor(config, eventEmitter, tokenManager) {
337
355
  this.config = config;
@@ -606,22 +624,22 @@ class SSEConnection {
606
624
  class OfferStore {
607
625
  constructor(config) {
608
626
  this.offers = new Map();
609
- this.playerSnapshot = null;
627
+ this.player = null;
610
628
  this.logger = createLogger(config, 'OfferStore');
611
629
  }
612
- getSnapshot() {
613
- return this.playerSnapshot;
630
+ getPlayer() {
631
+ return this.player || null;
614
632
  }
615
- setSnapshot(snapshot) {
616
- this.playerSnapshot = snapshot;
617
- this.logger.log('Updated player snapshot:', snapshot);
633
+ setPlayer(player) {
634
+ this.player = player;
635
+ this.logger.log('Updated player:', player);
618
636
  }
619
637
  /**
620
638
  * Set all offers (replaces existing)
621
639
  */
622
640
  setOffers(offers) {
623
641
  this.offers.clear();
624
- offers.forEach(offer => {
642
+ offers.forEach((offer) => {
625
643
  this.offers.set(offer.instanceId, offer);
626
644
  });
627
645
  this.logger.log(`Set ${offers.length} offers`);
@@ -661,16 +679,18 @@ class OfferStore {
661
679
  * Get offers filtered by status
662
680
  */
663
681
  getOffersByStatus(status) {
664
- return this.getAllOffers().filter(offer => offer.status === status);
682
+ return this.getAllOffers().filter((offer) => offer.status === status);
665
683
  }
666
684
  /**
667
685
  * Get active offers (not expired, not claimed)
668
686
  */
669
687
  getActiveOffers() {
670
- return this.getAllOffers().filter(offer => {
688
+ return this.getAllOffers().filter((offer) => {
671
689
  if (!offer.status)
672
690
  return false; // Must have a status
673
- return offer.status === 'surfaced' || offer.status === 'viewed' || offer.status === 'claimable';
691
+ return (offer.status === 'surfaced' ||
692
+ offer.status === 'viewed' ||
693
+ offer.status === 'claimable');
674
694
  });
675
695
  }
676
696
  /**
@@ -810,12 +830,11 @@ class AssetHelper {
810
830
  case 'exp':
811
831
  id = reward.skillId;
812
832
  break;
813
- case 'on_chain':
814
- id = reward.assetId;
815
- break;
816
833
  case 'trust_points':
817
834
  id = 'trust_points';
818
835
  break;
836
+ case 'loyalty_currency':
837
+ id = reward.currencyId;
819
838
  }
820
839
  // Fallback to reward's built-in name, we should add 5x popberry etc
821
840
  const formattedName = reward.amount > 1 ? `${reward.amount}x ${reward.name}` : reward.name;
@@ -825,38 +844,38 @@ class AssetHelper {
825
844
  if (content) {
826
845
  return {
827
846
  name: content.name || formattedName,
828
- image: content.image || this.config.fallbackRewardImage
847
+ image: content.image || this.config.fallbackRewardImage,
829
848
  };
830
849
  }
831
850
  }
832
851
  return {
833
852
  name: formattedName,
834
- image: this.config.fallbackRewardImage
853
+ image: this.config.fallbackRewardImage,
835
854
  };
836
855
  }
837
856
  resolveOfferRewards(offer) {
838
- return offer.rewards.map(reward => ({
857
+ return offer.rewards.map((reward) => ({
839
858
  ...reward,
840
859
  ...this.resolveReward(reward),
841
860
  }));
842
861
  }
843
862
  }
844
863
 
845
- const mapEnvToBuildOnApiUrl = (env) => {
864
+ const mapEnvToOfferClientUrl = (env) => {
846
865
  switch (env) {
847
866
  case 'live':
848
- return 'https://api.pixels.xyz';
867
+ return 'https://offers.pixels.xyz';
849
868
  case 'test':
850
- return 'https://api.sandbox.pixels.xyz';
869
+ return 'https://offers.sandbox.pixels.xyz';
851
870
  case 'staging':
852
- return 'https://api.staging.pixels.xyz';
871
+ return 'https://offers.staging.pixels.xyz';
853
872
  case 'preview':
854
- return 'https://api.preview.pixels.xyz';
873
+ return 'https://offers.preview.pixels.xyz';
855
874
  case 'dev':
856
875
  case 'development':
857
- return 'https://api.dev.pixels.xyz';
876
+ return 'https://offers.dev.pixels.xyz';
858
877
  default:
859
- return 'https://api.sandbox.pixels.xyz';
878
+ return 'https://offers.sandbox.pixels.xyz';
860
879
  }
861
880
  };
862
881
  class OfferwallClient {
@@ -913,7 +932,7 @@ class OfferwallClient {
913
932
  return;
914
933
  }
915
934
  this.isInitializing = true;
916
- await this.refreshOffersAndSnapshot();
935
+ await this.refreshOffersAndPlayer();
917
936
  await this.connect();
918
937
  this.isInitializing = false;
919
938
  }
@@ -1072,28 +1091,34 @@ class OfferwallClient {
1072
1091
  kind: 'offer',
1073
1092
  });
1074
1093
  }
1075
- async refreshOffersAndSnapshot() {
1094
+ getPlayer() {
1095
+ return this.offerStore.getPlayer();
1096
+ }
1097
+ getOffers() {
1098
+ return this.offerStore.getAllOffers();
1099
+ }
1100
+ async refreshOffersAndPlayer() {
1076
1101
  try {
1077
- const { offers, snapshot } = await this.getOffersAndSnapshot();
1102
+ const { offers, player } = await this.getOffersAndPlayer();
1078
1103
  this.offerStore.setOffers(offers);
1079
- this.offerStore.setSnapshot(snapshot);
1080
- this.eventEmitter.emit(OfferEvent.REFRESH, { offers, playerSnapshot: snapshot });
1104
+ this.offerStore.setPlayer(player);
1105
+ this.eventEmitter.emit(OfferEvent.REFRESH, { offers, player: player });
1081
1106
  this.logger.log('Refreshed offers and player snapshot');
1082
1107
  }
1083
1108
  catch (error) {
1084
- this.handleError(error, 'refreshOffersAndSnapshot');
1109
+ this.handleError(error, 'refreshOffersAndPlayer');
1085
1110
  throw error;
1086
1111
  }
1087
1112
  }
1088
- async getOffersAndSnapshot() {
1113
+ async getOffersAndPlayer() {
1089
1114
  const data = await this.postWithAuth('/v1/client/player/campaigns', {
1090
1115
  viewingCampaigns: true,
1091
1116
  });
1092
1117
  if (!data.offers || !Array.isArray(data.offers)) {
1093
1118
  throw new Error('No offers returned from offers endpoint');
1094
1119
  }
1095
- if (!data.snapshot) {
1096
- throw new Error('No player snapshot returned from offers endpoint');
1120
+ if (!data.player) {
1121
+ throw new Error('No player returned from offers endpoint');
1097
1122
  }
1098
1123
  return data;
1099
1124
  }
@@ -1116,6 +1141,14 @@ class OfferwallClient {
1116
1141
  return null;
1117
1142
  }
1118
1143
  }
1144
+ async getDashboardRedirectUrl() {
1145
+ const dashboardBaseUrl = mapEnvToOfferClientUrl(this.config.env);
1146
+ const token = await this.getAuthLinkToken();
1147
+ const gameId = this.getGameId();
1148
+ if (!token)
1149
+ return null;
1150
+ return `${dashboardBaseUrl}/auth/enter?token=${token}&gameId=${gameId}`;
1151
+ }
1119
1152
  handleError(error, context) {
1120
1153
  this.logger.error(`Error in ${context}:`, error);
1121
1154
  if (this.hooks.onError) {
@@ -1452,6 +1485,93 @@ const meetsBaseConditions = ({ conditions, playerSnap, addDetails, }) => {
1452
1485
  }
1453
1486
  return { isValid, conditionData: addDetails ? conditionData : undefined };
1454
1487
  };
1488
+ const meetsSurfacingConditions = ({ surfacingContexts, surfacingConditions, playerSnap, context, }) => {
1489
+ if (surfacingContexts?.length && !surfacingContexts.includes(context || '')) {
1490
+ // context is not in the list of surfacing contexts, so we don't want to surface this offer
1491
+ return { isValid: false };
1492
+ }
1493
+ const conditions = surfacingConditions;
1494
+ if (conditions?.andTags?.length) {
1495
+ // check if player has all of the tags
1496
+ const hasAllTags = conditions.andTags.every((tag) => playerSnap.tags?.includes(tag));
1497
+ if (!hasAllTags) {
1498
+ return { isValid: false };
1499
+ }
1500
+ }
1501
+ if (conditions?.orTags?.length) {
1502
+ // check if player has any of the tags
1503
+ const hasAnyTags = conditions.orTags.some((tag) => playerSnap.tags?.includes(tag));
1504
+ if (!hasAnyTags) {
1505
+ return { isValid: false };
1506
+ }
1507
+ }
1508
+ if (conditions?.notTags?.length) {
1509
+ // check if player has any of the tags
1510
+ const hasAnyTags = conditions.notTags.some((tag) => playerSnap.tags?.includes(tag));
1511
+ if (hasAnyTags) {
1512
+ return { isValid: false };
1513
+ }
1514
+ }
1515
+ if (conditions?.maxDaysInGame &&
1516
+ (playerSnap.daysInGame || Infinity) > conditions.maxDaysInGame) {
1517
+ return { isValid: false };
1518
+ }
1519
+ if (conditions.loginStreak && (playerSnap.loginStreak || 0) < conditions.loginStreak) {
1520
+ return { isValid: false };
1521
+ }
1522
+ // Check dynamic conditions if present
1523
+ if (conditions.dynamic?.conditions?.length) {
1524
+ if (!meetsDynamicConditions(playerSnap.dynamic || {}, conditions.dynamic)) {
1525
+ return { isValid: false };
1526
+ }
1527
+ }
1528
+ return meetsBaseConditions({ conditions, playerSnap });
1529
+ };
1530
+ const hasConditions = (conditions) => {
1531
+ if (!conditions)
1532
+ return false;
1533
+ if (Object.keys(conditions.currencies || {}).length > 0)
1534
+ return true;
1535
+ if (Object.keys(conditions.levels || {}).length > 0)
1536
+ return true;
1537
+ if (Object.keys(conditions.stakedTokens || {}).length > 0)
1538
+ return true;
1539
+ if (Object.keys(conditions.memberships || {}).length > 0)
1540
+ return true;
1541
+ if (Object.keys(conditions.quests || {}).length > 0)
1542
+ return true;
1543
+ if (conditions.minTrustScore)
1544
+ return true;
1545
+ if (conditions.maxTrustScore)
1546
+ return true;
1547
+ if (conditions.achievements)
1548
+ return true;
1549
+ if (conditions.minDaysInGame)
1550
+ return true;
1551
+ const surCond = conditions;
1552
+ if (surCond.andTags?.length)
1553
+ return true;
1554
+ if (surCond.orTags?.length)
1555
+ return true;
1556
+ if (surCond.notTags?.length)
1557
+ return true;
1558
+ if (surCond.maxDaysInGame)
1559
+ return true;
1560
+ if (surCond.loginStreak)
1561
+ return true;
1562
+ const compCond = conditions;
1563
+ if (compCond.buyItem)
1564
+ return true;
1565
+ if (compCond.spendCurrency)
1566
+ return true;
1567
+ if (compCond.depositCurrency)
1568
+ return true;
1569
+ if (compCond.login)
1570
+ return true;
1571
+ if (compCond.loginStreak)
1572
+ return true;
1573
+ return false;
1574
+ };
1455
1575
  const meetsCompletionConditions = ({ completionConditions, completionTrackers, playerSnap, addDetails = false, }) => {
1456
1576
  if (completionConditions) {
1457
1577
  const conditions = completionConditions;
@@ -1554,8 +1674,84 @@ const meetsCompletionConditions = ({ completionConditions, completionTrackers, p
1554
1674
  }
1555
1675
  return { isValid: true, conditionData: [] };
1556
1676
  };
1677
+ /**
1678
+ * Checks if a dynamic object meets a set of dynamic field conditions.
1679
+ * @param dynamicObj - The object with any key and string or number value.
1680
+ * @param conditions - Array of conditions to check.
1681
+ * @returns true if all conditions are met, false otherwise.
1682
+ */
1683
+ /**
1684
+ * Evaluates a single dynamic condition against the dynamic object.
1685
+ */
1686
+ function evaluateDynamicCondition(dynamicObj, cond) {
1687
+ const val = dynamicObj[cond.key];
1688
+ if (val === undefined)
1689
+ return false;
1690
+ switch (cond.operator) {
1691
+ case '==':
1692
+ return val === cond.compareTo;
1693
+ case '!=':
1694
+ return val !== cond.compareTo;
1695
+ case '>':
1696
+ return (typeof val === 'number' &&
1697
+ typeof cond.compareTo === 'number' &&
1698
+ val > cond.compareTo);
1699
+ case '>=':
1700
+ return (typeof val === 'number' &&
1701
+ typeof cond.compareTo === 'number' &&
1702
+ val >= cond.compareTo);
1703
+ case '<':
1704
+ return (typeof val === 'number' &&
1705
+ typeof cond.compareTo === 'number' &&
1706
+ val < cond.compareTo);
1707
+ case '<=':
1708
+ return (typeof val === 'number' &&
1709
+ typeof cond.compareTo === 'number' &&
1710
+ val <= cond.compareTo);
1711
+ case 'has':
1712
+ return (typeof val === 'string' &&
1713
+ typeof cond.compareTo === 'string' &&
1714
+ val.includes(cond.compareTo));
1715
+ case 'not_has':
1716
+ return (typeof val === 'string' &&
1717
+ typeof cond.compareTo === 'string' &&
1718
+ !val.includes(cond.compareTo));
1719
+ default:
1720
+ return false;
1721
+ }
1722
+ }
1723
+ /**
1724
+ * Evaluates a group of dynamic conditions with logical links (AND, OR, AND NOT).
1725
+ * @param dynamicObj - The player's dynamic object with any key and string or number value.
1726
+ * @param dynamicGroup - The group of conditions and links to check.
1727
+ * @returns true if the group evaluates to true, false otherwise.
1728
+ */
1729
+ function meetsDynamicConditions(dynamicObj, dynamicGroup) {
1730
+ const { conditions, links } = dynamicGroup;
1731
+ if (!conditions || conditions.length === 0)
1732
+ return true;
1733
+ // If no links, treat as AND between all conditions
1734
+ if (!links || links.length === 0) {
1735
+ return conditions.every((cond) => evaluateDynamicCondition(dynamicObj, cond));
1736
+ }
1737
+ // Evaluate the first condition
1738
+ let result = evaluateDynamicCondition(dynamicObj, conditions[0]);
1739
+ for (let i = 0; i < links.length; i++) {
1740
+ const nextCond = evaluateDynamicCondition(dynamicObj, conditions[i + 1]);
1741
+ const link = links[i];
1742
+ if (link === 'AND') {
1743
+ result = result && nextCond;
1744
+ }
1745
+ else if (link === 'OR') {
1746
+ result = result || nextCond;
1747
+ }
1748
+ else if (link === 'AND NOT') {
1749
+ result = result && !nextCond;
1750
+ }
1751
+ }
1752
+ return result;
1753
+ }
1557
1754
 
1558
- // Taken from buildon_server/src/commons/types/offer.ts and merged into a single interface
1559
1755
  const PlayerOfferStatuses = [
1560
1756
  'inQueue',
1561
1757
  'surfaced',
@@ -1565,16 +1761,26 @@ const PlayerOfferStatuses = [
1565
1761
  'expired',
1566
1762
  ];
1567
1763
 
1568
- // Taken from buildon_server/src/commons/types/reward.ts
1569
1764
  // Use a const assertion for the array and infer the union type directly
1570
1765
  const rewardKinds = [
1571
1766
  'item',
1572
1767
  'coins',
1573
1768
  'exp',
1574
1769
  'trust_points',
1770
+ 'loyalty_currency', // loyalty currency that the player can exchange for rewards like on-chain via withdraw, etc.
1575
1771
  /** on-chain rewards require the builder to send funds to a custodial wallet that we use to send to player wallets*/
1576
- 'on_chain',
1577
1772
  ];
1773
+ const rewardSchema = {
1774
+ _id: false,
1775
+ kind: { type: String, enum: rewardKinds },
1776
+ rewardId: String,
1777
+ skillId: String,
1778
+ currencyId: String, // could be a loyalty currency
1779
+ itemId: String,
1780
+ amount: Number,
1781
+ name: String,
1782
+ image: String,
1783
+ };
1578
1784
 
1579
- export { AssetHelper, ConnectionState, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, meetsBaseConditions, meetsCompletionConditions, rewardKinds };
1785
+ export { AssetHelper, ConnectionState, EventEmitter, OfferEvent, OfferStore, OfferwallClient, PlayerOfferStatuses, SSEConnection, hasConditions, meetsBaseConditions, meetsCompletionConditions, meetsDynamicConditions, meetsSurfacingConditions, rewardKinds, rewardSchema };
1580
1786
  //# sourceMappingURL=index.esm.js.map