@pixels-online/pixels-client-js-sdk 1.14.0 → 1.16.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.
@@ -1,4 +1,5 @@
1
- import { IBlockchainSyncStatus, ICryptoBalance } from './user_wallet';
1
+ import { Stringable } from '.';
2
+ import { IBlockchainSyncStatus } from './blockchain/user_wallet';
2
3
  export type IClientPlayer = {
3
4
  snapshot: Omit<IPlayerSnapshot, 'tags' | 'tagsLastUpdated'>;
4
5
  data?: IPlayerData | null;
@@ -7,10 +8,12 @@ export interface IPlayerSnapshot {
7
8
  _id: string;
8
9
  gameId: string;
9
10
  playerId: string;
11
+ /** when this was last linked to a unified user */
12
+ unifiedUserLinkedAt?: number;
13
+ /** when this was last unlinked to a unified user */
14
+ unifiedUserUnlinkedAt?: number;
10
15
  /** player that referred this player to this game */
11
16
  referredById?: string;
12
- /** did this player complete referee and can claim rewards now? Store this here so we don't need to do another db lookup */
13
- refereeRewardsClaimable?: boolean;
14
17
  username?: string;
15
18
  snapshotLastUpdated: number;
16
19
  offersLastChecked?: number;
@@ -56,20 +59,30 @@ export interface IPlayerSnapshot {
56
59
  expiresAt?: number;
57
60
  lastUpdated?: number;
58
61
  }>;
62
+ /** auth identifiers. like social tiktok or email or sms or whatever */
63
+ identifiers?: Array<{
64
+ /** id */
65
+ identifier: string;
66
+ /** sms/email/tiktok etc */
67
+ platform: string;
68
+ lastUpdated: number;
69
+ }>;
59
70
  cryptoWallets?: Array<{
60
71
  address: string;
61
72
  lastUpdated?: number;
62
73
  }>;
63
- /** wallets that this player has sent on-chain rewards to */
64
- rewardWallets?: Array<{
65
- address: string;
66
- /** list of chains that this wallet has received funds from */
67
- chainIds: Array<number>;
68
- /** list of contract IDs that this wallet has received funds from */
69
- contractIds: Array<string>;
70
- }>;
71
74
  tags?: Array<string>;
72
75
  tagsLastUpdated?: number;
76
+ entityKind?: string;
77
+ /**
78
+ * Links to other entities (players, pets, guilds, etc.)
79
+ */
80
+ entityLinks?: Array<{
81
+ /** if undefined, it means same game */
82
+ gameId?: string;
83
+ playerId: string;
84
+ kind?: string;
85
+ }>;
73
86
  /**
74
87
  * collection of information about IP address player connected from
75
88
  */
@@ -82,10 +95,30 @@ export type Restriction = {
82
95
  eventCount: number;
83
96
  message?: string;
84
97
  };
98
+ export interface IPlayerDataCurrency {
99
+ /**
100
+ * balance held
101
+ */
102
+ balance: number;
103
+ /**
104
+ * total amount deposited
105
+ */
106
+ in?: number;
107
+ /**
108
+ * total amount withdrawn
109
+ */
110
+ out?: number;
111
+ /**
112
+ * last updated timestamp
113
+ * if not present, means never updated
114
+ */
115
+ lastUpdated?: number;
116
+ }
85
117
  export interface IPlayerData {
118
+ _id?: Stringable;
86
119
  gameId: string;
87
120
  playerId: string;
88
- currencies?: Record<string, ICryptoBalance>;
121
+ currencies?: Record<string, IPlayerDataCurrency>;
89
122
  blockchainSync?: Record<string, IBlockchainSyncStatus>;
90
123
  restriction?: Restriction;
91
124
  }
@@ -165,6 +198,26 @@ export interface IBaseCondition {
165
198
  /** if a min number of quest completions is required */
166
199
  completions?: number;
167
200
  }>;
201
+ /**
202
+ * For player snapshot entities that are linked to other player snap entities,
203
+ * what are the min and max number of links of a specific link kind?
204
+ * Keys are link kinds (e.g., "pet", "guild", "npc", etc.)
205
+ */
206
+ links?: Record<string, {
207
+ /** minimum number of links of this type required */
208
+ min?: number;
209
+ /** maximum number of links of this type allowed */
210
+ max?: number;
211
+ }>;
212
+ /** dynamic field conditions */
213
+ dynamic?: IDynamicGroup;
214
+ /** Auth platform identifiers condition */
215
+ identifiers?: {
216
+ /** List of auth platforms to check (e.g., 'tiktok', 'google', 'email') */
217
+ platforms: string[];
218
+ /** 'AND' = player must have ALL platforms, 'OR' = player must have ANY platform */
219
+ behaviour: 'AND' | 'OR';
220
+ };
168
221
  }
169
222
  export interface ISurfacingCondition extends IBaseCondition {
170
223
  /** number of days that the player has logged in-game. Not the absolute amount of time playing the game. But number of days they have logged in for.
@@ -177,8 +230,6 @@ export interface ISurfacingCondition extends IBaseCondition {
177
230
  orTags?: Array<string>;
178
231
  /** player cannot have any of these tags */
179
232
  notTags?: Array<string>;
180
- /** dynamic field conditions for surfacing */
181
- dynamic?: IDynamicGroup;
182
233
  /** minimum signup date (timestamp) - player must have signed up after this date */
183
234
  minDateSignedUp?: number;
184
235
  /** maximum signup date (timestamp) - player must have signed up before this date */
@@ -189,6 +240,8 @@ export interface ISurfacingCondition extends IBaseCondition {
189
240
  contexts?: Array<string>;
190
241
  /** if true, offer can only be surfaced programmatically (e.g., via spawnLinkedOffer) - never through normal auto-surfacing */
191
242
  programmatic?: boolean;
243
+ /** entity types that this offer can surface to - undefined or empty means only regular players. */
244
+ targetEntityTypes?: string[];
192
245
  }
193
246
  /** conditions that must be met for an already surfaced offer to be claimable */
194
247
  export interface ICompletionCondition extends IBaseCondition {
@@ -215,6 +268,8 @@ export interface ICompletionCondition extends IBaseCondition {
215
268
  };
216
269
  /** social media content condition - player must attach content meeting requirements */
217
270
  social?: {
271
+ /** 'attach' (default) = user attaches single content, 'accumulate' = auto-sum all matching content */
272
+ mode?: 'attach' | 'accumulate';
218
273
  /** platforms accepted (OR logic) - e.g., ['tiktok', 'instagram', 'youtube'] */
219
274
  platforms: string[];
220
275
  /** words that must ALL appear in video title or description (case-insensitive). Hashtags must match exactly including # */
@@ -235,6 +290,19 @@ export interface ICompletionCondition extends IBaseCondition {
235
290
  id: string;
236
291
  name: string;
237
292
  };
293
+ /**
294
+ * Linked completions - wait for N linked entities to complete their offers
295
+ */
296
+ linkedCompletions?: {
297
+ /** Number of linked entity completions required */
298
+ min: number;
299
+ };
300
+ /**
301
+ * Dynamic field tracker - tracks changes to dynamic fields AFTER offer surfacing.
302
+ * Unlike the base `dynamic` condition which checks snapshot totals,
303
+ * this tracks per-offer values since surfacing.
304
+ */
305
+ dynamicTracker?: IDynamicGroup;
238
306
  }
239
307
  /**
240
308
  * TypeScript interface for dynamicGroupSchema
@@ -252,6 +320,44 @@ export type DynamicConditionLink = 'AND' | 'OR' | 'AND NOT';
252
320
  export interface IDynamicGroup {
253
321
  conditions: Array<IDynamicCondition>;
254
322
  links?: Array<DynamicConditionLink>;
323
+ /** Display template using {keyName} syntax for referenced dynamic keys */
324
+ template?: string;
325
+ }
326
+ /** Social tracker for attach mode - user manually attaches a single piece of content */
327
+ export interface ISocialTrackerAttach {
328
+ /** 'attach' or undefined = user-attached single content */
329
+ mode?: 'attach';
330
+ /** platform name - tiktok, instagram, or youtube */
331
+ platform: string;
332
+ /** video ID on the platform */
333
+ videoId: string;
334
+ /** platform specific user ID */
335
+ userId: string;
336
+ /** cached video title for display */
337
+ title?: string;
338
+ /** cached view count */
339
+ views: number;
340
+ /** cached like count */
341
+ likes?: number;
342
+ /** cached comment count */
343
+ comments?: number;
344
+ /** timestamp of last validation check (for 5-minute cache) */
345
+ lastChecked: Date;
346
+ }
347
+ /** Social tracker for accumulate mode - auto-sum all matching content */
348
+ export interface ISocialTrackerAccumulate {
349
+ /** 'accumulate' = auto-sum all matching content */
350
+ mode: 'accumulate';
351
+ /** sum of view counts across all matching content */
352
+ views: number;
353
+ /** sum of like counts across all matching content */
354
+ likes?: number;
355
+ /** sum of comment counts across all matching content */
356
+ comments?: number;
357
+ /** timestamp of last validation check (for 5-minute cache) */
358
+ lastChecked: Date;
359
+ /** number of matching content items */
360
+ matchCount: number;
255
361
  }
256
362
  /** tracking the player's status for completing the conditions to claim the offer, if
257
363
  * required.
@@ -266,25 +372,19 @@ export interface ICompletionTrackers {
266
372
  /** the number of days that have been consecutively logged in at the time of surfacing this offer */
267
373
  currentLoginStreak?: number;
268
374
  /** tracks attached social media content and cached validation state */
269
- social?: {
270
- /** platform name - tiktok, instagram, or youtube */
271
- platform: string;
272
- /** video ID on the platform */
273
- videoId: string;
274
- /** cached video title for display */
275
- title?: string;
276
- /** cached view count */
277
- views: number;
278
- /** cached like count */
279
- likes?: number;
280
- /** cached comment count */
281
- comments?: number;
282
- /** timestamp of last validation check (for 1-hour cache) */
283
- lastChecked: Date;
284
- /** platform specific user ID */
285
- userId: string;
286
- };
375
+ social?: ISocialTrackerAttach | ISocialTrackerAccumulate;
287
376
  login?: boolean;
288
377
  /** completed context for this player */
289
378
  context?: string;
379
+ /**
380
+ * Count of linked entities that have completed their offers.
381
+ * For example a referrer refers 5 other referees that have all
382
+ * completed the referral criteria. this would then be a value of 5.
383
+ */
384
+ linkedCompletions?: number;
385
+ /**
386
+ * Tracked dynamic field values per key.
387
+ * Key = dynamic field key, Value = tracked value since offer surfaced
388
+ */
389
+ dynamicTracker?: Record<string, string | number>;
290
390
  }
@@ -4,12 +4,6 @@ export interface IReward {
4
4
  /** if the trigger is type daily-login, which day is this reward for? */
5
5
  /** reward id for rewards of kind item, coins, exp or loyalty currency */
6
6
  rewardId?: string;
7
- /** @deprecated in favour of rewardId */
8
- skillId?: string;
9
- /** @deprecated in favour of rewardId */
10
- currencyId?: string;
11
- /** @deprecated in favour of rewardId */
12
- itemId?: string;
13
7
  /** amount of reward to give. If kind is discount, then this refers to the discount amount, as a fraction */
14
8
  amount: number;
15
9
  /** public facing name for this reward */
@@ -18,17 +12,24 @@ export interface IReward {
18
12
  image?: string;
19
13
  }
20
14
  export type RewardKind = (typeof rewardKinds)[number];
15
+ /** for client side sdk */
21
16
  export interface IResolvedReward extends IReward {
22
17
  image?: string;
23
18
  }
24
- export declare const rewardKinds: readonly ["item", "coins", "exp", "trust_points", "loyalty_currency"];
19
+ export declare const rewardKinds: readonly ["item", "coins", "exp", "trust_points", "loyalty_currency", "discount"];
25
20
  export declare const rewardSchema: {
26
21
  _id: boolean;
27
22
  kind: {
28
23
  type: StringConstructor;
29
- enum: readonly ["item", "coins", "exp", "trust_points", "loyalty_currency"];
24
+ enum: readonly ["item", "coins", "exp", "trust_points", "loyalty_currency", "discount"];
25
+ };
26
+ rewardId: {
27
+ type: StringConstructor;
28
+ validate: {
29
+ validator: (this: IReward, value: string | undefined) => boolean;
30
+ message: string;
31
+ };
30
32
  };
31
- rewardId: StringConstructor;
32
33
  skillId: StringConstructor;
33
34
  currencyId: StringConstructor;
34
35
  itemId: StringConstructor;
@@ -1,9 +1,9 @@
1
1
  import { ISurfacingCondition, IPlayerSnapshot, ICompletionCondition, IBaseCondition, ICompletionTrackers } from '../types/player';
2
2
  import { IDynamicGroup } from '../types/player';
3
- import { IPlayerOffer } from '../types/offer';
3
+ import { IOffer, IPlayerOffer, IPlayerOfferTrackers, IStrippedSnapshot } from '../types/offer';
4
4
  export declare const meetsBaseConditions: ({ conditions, playerSnap, addDetails, }: {
5
5
  conditions: IBaseCondition;
6
- playerSnap: IPlayerSnapshot;
6
+ playerSnap: IPlayerSnapshot | IStrippedSnapshot;
7
7
  addDetails?: boolean;
8
8
  }) => {
9
9
  isValid: boolean;
@@ -38,7 +38,7 @@ export declare const hasConditions: (conditions: ICompletionCondition | ISurfaci
38
38
  export declare const meetsCompletionConditions: ({ completionConditions, completionTrackers, playerSnap, addDetails, }: {
39
39
  completionConditions: ICompletionCondition;
40
40
  completionTrackers?: ICompletionTrackers;
41
- playerSnap: IPlayerSnapshot;
41
+ playerSnap: IPlayerSnapshot | IStrippedSnapshot;
42
42
  addDetails?: boolean;
43
43
  }) => {
44
44
  isValid: boolean;
@@ -52,6 +52,22 @@ export declare const meetsCompletionConditions: ({ completionConditions, complet
52
52
  text: string;
53
53
  }[];
54
54
  };
55
+ /**
56
+ * Checks if completion conditions were met before a specific expiry time.
57
+ * Returns true if all relevant condition fields were updated before expiryTime.
58
+ *
59
+ * @param completionConditions - The completion conditions to check
60
+ * @param completionTrackers - The completion trackers (for buyItem, spendCurrency, etc.)
61
+ * @param playerSnap - The player snapshot with field timestamps
62
+ * @param expiryTime - The expiry timestamp in milliseconds
63
+ * @returns true if all conditions were met before expiry, false otherwise
64
+ */
65
+ export declare const meetsCompletionConditionsBeforeExpiry: ({ completionConditions, completionTrackers, playerSnap, expiryTime, }: {
66
+ completionConditions: ICompletionCondition;
67
+ completionTrackers?: ICompletionTrackers;
68
+ playerSnap: IPlayerSnapshot;
69
+ expiryTime: number;
70
+ }) => boolean;
55
71
  /**
56
72
  * Evaluates a group of dynamic conditions with logical links (AND, OR, AND NOT).
57
73
  * @param dynamicObj - The player's dynamic object with any key and string or number value.
@@ -59,3 +75,15 @@ export declare const meetsCompletionConditions: ({ completionConditions, complet
59
75
  * @returns true if the group evaluates to true, false otherwise.
60
76
  */
61
77
  export declare function meetsDynamicConditions(dynamicObj: Record<string, string | number>, dynamicGroup: IDynamicGroup): boolean;
78
+ /**
79
+ * Checks if a PlayerOffer meets its claimable conditions (completed -> claimable transition).
80
+ * @param claimableConditions - The offer's claimableConditions (from IOffer)
81
+ * @param claimableTrackers - The player offer's claimableTrackers
82
+ */
83
+ export declare function meetsClaimableConditions({ claimableConditions, playerOfferTrackers, claimableTrackers, }: {
84
+ claimableConditions?: IOffer['claimableConditions'];
85
+ playerOfferTrackers?: IPlayerOfferTrackers;
86
+ claimableTrackers?: IPlayerOffer['claimableTrackers'];
87
+ }): {
88
+ isValid: boolean;
89
+ };
@@ -0,0 +1,2 @@
1
+ export declare function extractTemplateKeys(template: string | undefined): Set<string>;
2
+ export declare function renderTemplate(template: string | undefined, dynamic: Record<string, string | number> | undefined): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixels-online/pixels-client-js-sdk",
3
- "version": "1.14.0",
3
+ "version": "1.16.0",
4
4
  "description": "Pixels Client JS SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -67,6 +67,7 @@
67
67
  "prettier": "^3.6.2",
68
68
  "rimraf": "^6.0.1",
69
69
  "rollup": "^4.50.1",
70
+ "semantic-release": "25.0.2",
70
71
  "ts-jest": "^29.4.1",
71
72
  "ts-node": "^10.9.2",
72
73
  "tslib": "^2.8.1",