@opexa/portal-sdk 0.59.88 → 0.59.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3838,6 +3838,79 @@ var MEMBER_FREE_BET_DROPS_QUERY = gql`
3838
3838
  }
3839
3839
  }
3840
3840
  `;
3841
+ var _GAMES_QUERY = gql`
3842
+ query _Games($first: Int, $after: Cursor, $filter: GameFilterInput) {
3843
+ games(first: $first, after: $after, filter: $filter) {
3844
+ edges {
3845
+ cursor
3846
+ node {
3847
+ ... on Game {
3848
+ id
3849
+ name
3850
+ displayName
3851
+ type
3852
+ provider
3853
+ reference
3854
+ hidden
3855
+ image
3856
+ }
3857
+ }
3858
+ }
3859
+ pageInfo {
3860
+ hasNextPage
3861
+ endCursor
3862
+ }
3863
+ }
3864
+ }
3865
+ `;
3866
+ var _GAME_GROUPS_QUERY = gql`
3867
+ query _GameGroups {
3868
+ gameGroups {
3869
+ id
3870
+ name
3871
+ }
3872
+ }
3873
+ `;
3874
+ var _GAME_GROUP_NODE_QUERY = gql`
3875
+ query _GameGroupNode($id: ObjectId!, $limit: Int, $offset: Int) {
3876
+ node(id: $id) {
3877
+ ... on GameGroup {
3878
+ id
3879
+ name
3880
+ games(limit: $limit, offset: $offset) {
3881
+ id
3882
+ name
3883
+ displayName
3884
+ type
3885
+ provider
3886
+ reference
3887
+ hidden
3888
+ image
3889
+ }
3890
+ }
3891
+ }
3892
+ }
3893
+ `;
3894
+ var _GAME_NODE_QUERY = gql`
3895
+ query _GameNode($id: ObjectId!) {
3896
+ node(id: $id) {
3897
+ ... on Game {
3898
+ id
3899
+ name
3900
+ displayName
3901
+ type
3902
+ provider
3903
+ reference
3904
+ hidden
3905
+ image
3906
+ groups {
3907
+ id
3908
+ name
3909
+ }
3910
+ }
3911
+ }
3912
+ }
3913
+ `;
3841
3914
 
3842
3915
  // src/services/utils.ts
3843
3916
  function createOperationError(code) {
@@ -4765,6 +4838,12 @@ var AuthService = class {
4765
4838
  error: createOperationError("AccountSuspendedError")
4766
4839
  };
4767
4840
  }
4841
+ if (body.code === "REFRESH_TOKEN_EXPIRED") {
4842
+ return {
4843
+ ok: false,
4844
+ error: createOperationError("SessionExpiredError")
4845
+ };
4846
+ }
4768
4847
  if (res.status === 403 || res.status === 401) {
4769
4848
  return {
4770
4849
  ok: false,
@@ -5242,6 +5321,66 @@ var PortalService = class {
5242
5321
  data: res.data
5243
5322
  };
5244
5323
  }
5324
+ async _games(variables) {
5325
+ const res = await this.client.request(
5326
+ _GAMES_QUERY,
5327
+ variables
5328
+ );
5329
+ if (!res.ok) return res;
5330
+ if (!res.data.games) {
5331
+ return {
5332
+ ok: false,
5333
+ error: {
5334
+ name: "UnknownError",
5335
+ message: "Something went wrong."
5336
+ }
5337
+ };
5338
+ }
5339
+ return {
5340
+ ok: true,
5341
+ data: res.data.games
5342
+ };
5343
+ }
5344
+ async _gameGroups() {
5345
+ const res = await this.client.request(
5346
+ _GAME_GROUPS_QUERY
5347
+ );
5348
+ if (!res.ok) return res;
5349
+ if (!res.data.gameGroups) {
5350
+ return {
5351
+ ok: false,
5352
+ error: {
5353
+ name: "UnknownError",
5354
+ message: "Something went wrong."
5355
+ }
5356
+ };
5357
+ }
5358
+ return {
5359
+ ok: true,
5360
+ data: res.data.gameGroups
5361
+ };
5362
+ }
5363
+ async _gameGroupNode(id, limit, offset) {
5364
+ const res = await this.client.request(
5365
+ _GAME_GROUP_NODE_QUERY,
5366
+ { id, limit, offset }
5367
+ );
5368
+ if (!res.ok) return res;
5369
+ return {
5370
+ ok: true,
5371
+ data: res.data.node
5372
+ };
5373
+ }
5374
+ async _gameNode(id) {
5375
+ const res = await this.client.request(_GAME_NODE_QUERY, {
5376
+ id
5377
+ });
5378
+ if (!res.ok) return res;
5379
+ return {
5380
+ ok: true,
5381
+ data: res.data.node
5382
+ };
5383
+ }
5245
5384
  async recommendedGames() {
5246
5385
  const res = await this.client.request(
5247
5386
  RECOMMENDED_GAMES_QUERY
@@ -7351,7 +7490,8 @@ var SessionManager = class {
7351
7490
  if (input.type === "MOBILE_NUMBER") {
7352
7491
  const res2 = await this.authService.createSession(input, version);
7353
7492
  if (res2.ok) {
7354
- if (!this.persist(res2.data, version)) return this.malformedResponseError();
7493
+ if (!this.persist(res2.data, version))
7494
+ return this.malformedResponseError();
7355
7495
  return {
7356
7496
  ok: true,
7357
7497
  data: null
@@ -7369,7 +7509,8 @@ var SessionManager = class {
7369
7509
  version
7370
7510
  );
7371
7511
  if (res2.ok) {
7372
- if (!this.persist(res2.data, version)) return this.malformedResponseError();
7512
+ if (!this.persist(res2.data, version))
7513
+ return this.malformedResponseError();
7373
7514
  return {
7374
7515
  ok: true,
7375
7516
  data: null
@@ -7381,7 +7522,8 @@ var SessionManager = class {
7381
7522
  localStorage.setItem(this.platformStorageKey, "CABINET");
7382
7523
  const res2 = await this.authService.createSession(input, version);
7383
7524
  if (res2.ok) {
7384
- if (!this.persist(res2.data, version)) return this.malformedResponseError();
7525
+ if (!this.persist(res2.data, version))
7526
+ return this.malformedResponseError();
7385
7527
  return {
7386
7528
  ok: true,
7387
7529
  data: null
@@ -7605,7 +7747,7 @@ var SessionManager = class {
7605
7747
  this.refreshing = false;
7606
7748
  if (!res.ok) {
7607
7749
  this.logger.error(`Failed to refresh session: ${res.error.message}`);
7608
- if (res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError") {
7750
+ if (res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError" || res.error.name === "SessionExpiredError") {
7609
7751
  this.v4AccessToken = null;
7610
7752
  this.v4AccessTokenExpiresAt = null;
7611
7753
  }
@@ -7652,35 +7794,38 @@ var SessionManager = class {
7652
7794
  async verify() {
7653
7795
  if (this.isServer) {
7654
7796
  this.logger.warn("'localStorage' is not available on the server.");
7655
- return true;
7797
+ return { valid: true };
7656
7798
  }
7657
7799
  const val = localStorage.getItem(this.storageKey);
7658
7800
  if (val) {
7659
7801
  try {
7660
7802
  const stored = JSON.parse(val);
7661
7803
  if (stored.version === 4) {
7662
- const valid = await this.verifyV4(stored.session);
7663
- if (!valid) localStorage.removeItem(this.storageKey);
7664
- return valid;
7804
+ const res = await this.verifyV4(stored.session);
7805
+ if (!res.valid) localStorage.removeItem(this.storageKey);
7806
+ return res;
7665
7807
  }
7666
7808
  } catch {
7667
7809
  }
7668
7810
  }
7669
7811
  const s = await this.get();
7670
- if (s.error?.name === "InvalidTokenError") return false;
7671
- if (s.error?.name === "SessionExpiredError") return false;
7672
- if (s.error?.name === "AccountBlacklistedError") return false;
7673
- if (!s.data) return true;
7812
+ if (s.error?.name === "InvalidTokenError" || s.error?.name === "SessionExpiredError" || s.error?.name === "AccountBlacklistedError") {
7813
+ return { valid: false, reason: "INVALID_SESSION" };
7814
+ }
7815
+ if (!s.data) return { valid: true };
7674
7816
  const v = await this.authService.verifySession(s.data.accessToken);
7675
7817
  if (!v) {
7676
7818
  localStorage.removeItem(this.storageKey);
7677
7819
  }
7678
- return v;
7820
+ return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
7679
7821
  }
7680
7822
  async verifyV4(session) {
7681
7823
  if (!this.v4AccessToken || !this.v4AccessTokenExpiresAt || isAfter(/* @__PURE__ */ new Date(), new Date(this.v4AccessTokenExpiresAt))) {
7682
7824
  const res = await this.refreshV4(session);
7683
- return res.ok;
7825
+ return res.ok ? { valid: true } : {
7826
+ valid: false,
7827
+ reason: res.error.name === "SessionExpiredError" ? "REFRESH_TOKEN_EXPIRED" : "INVALID_SESSION"
7828
+ };
7684
7829
  }
7685
7830
  const v = await this.authService.verifySession(this.v4AccessToken);
7686
7831
  if (!v) {
@@ -7688,7 +7833,7 @@ var SessionManager = class {
7688
7833
  this.v4AccessToken = null;
7689
7834
  this.v4AccessTokenExpiresAt = null;
7690
7835
  }
7691
- return v;
7836
+ return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
7692
7837
  }
7693
7838
  get onMaya() {
7694
7839
  if (this.isServer) {
@@ -8039,7 +8184,7 @@ var SessionManagerCookie = class {
8039
8184
  this.refreshing = false;
8040
8185
  if (!res.ok) {
8041
8186
  this.logger.error(`Failed to refresh session: ${res.error.message}`);
8042
- if (res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError") {
8187
+ if (res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError" || res.error.name === "SessionExpiredError") {
8043
8188
  this.v4AccessToken = null;
8044
8189
  this.v4AccessTokenExpiresAt = null;
8045
8190
  }
@@ -8086,35 +8231,38 @@ var SessionManagerCookie = class {
8086
8231
  async verify() {
8087
8232
  if (this.isServer) {
8088
8233
  this.logger.warn("'client cookies' is not available on the server.");
8089
- return true;
8234
+ return { valid: true };
8090
8235
  }
8091
8236
  const val = cookies__default.default.get(this.storageKey);
8092
8237
  if (val) {
8093
8238
  try {
8094
8239
  const stored = JSON.parse(val);
8095
8240
  if (stored.version === 4) {
8096
- const valid = await this.verifyV4(stored.session);
8097
- if (!valid) cookies__default.default.remove(this.storageKey);
8098
- return valid;
8241
+ const res = await this.verifyV4(stored.session);
8242
+ if (!res.valid) cookies__default.default.remove(this.storageKey);
8243
+ return res;
8099
8244
  }
8100
8245
  } catch {
8101
8246
  }
8102
8247
  }
8103
8248
  const s = await this.get();
8104
- if (s.error?.name === "InvalidTokenError") return false;
8105
- if (s.error?.name === "SessionExpiredError") return false;
8106
- if (s.error?.name === "AccountBlacklistedError") return false;
8107
- if (!s.data) return true;
8249
+ if (s.error?.name === "InvalidTokenError" || s.error?.name === "SessionExpiredError" || s.error?.name === "AccountBlacklistedError") {
8250
+ return { valid: false, reason: "INVALID_SESSION" };
8251
+ }
8252
+ if (!s.data) return { valid: true };
8108
8253
  const v = await this.authService.verifySession(s.data.accessToken);
8109
8254
  if (!v) {
8110
8255
  cookies__default.default.remove(this.storageKey);
8111
8256
  }
8112
- return v;
8257
+ return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
8113
8258
  }
8114
8259
  async verifyV4(session) {
8115
8260
  if (!this.v4AccessToken || !this.v4AccessTokenExpiresAt || isAfter(/* @__PURE__ */ new Date(), new Date(this.v4AccessTokenExpiresAt))) {
8116
8261
  const res = await this.refreshV4(session);
8117
- return res.ok;
8262
+ return res.ok ? { valid: true } : {
8263
+ valid: false,
8264
+ reason: res.error.name === "SessionExpiredError" ? "REFRESH_TOKEN_EXPIRED" : "INVALID_SESSION"
8265
+ };
8118
8266
  }
8119
8267
  const v = await this.authService.verifySession(this.v4AccessToken);
8120
8268
  if (!v) {
@@ -8122,7 +8270,7 @@ var SessionManagerCookie = class {
8122
8270
  this.v4AccessToken = null;
8123
8271
  this.v4AccessTokenExpiresAt = null;
8124
8272
  }
8125
- return v;
8273
+ return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
8126
8274
  }
8127
8275
  get onMaya() {
8128
8276
  if (this.isServer) {
@@ -10433,10 +10581,10 @@ var Sdk = class {
10433
10581
  try {
10434
10582
  res = await this.sessionManager.verify();
10435
10583
  } catch {
10436
- res = false;
10584
+ res = { valid: false, reason: "INVALID_SESSION" };
10437
10585
  }
10438
- if (!res) {
10439
- await input.onInvalid();
10586
+ if (!res.valid) {
10587
+ await input.onInvalid(res.reason ?? "INVALID_SESSION");
10440
10588
  }
10441
10589
  }
10442
10590
  timeout = assignTimeout();
@@ -11811,6 +11959,92 @@ var Sdk = class {
11811
11959
  data: res.data ?? null
11812
11960
  };
11813
11961
  }
11962
+ /**
11963
+ * Fetches platform-scoped games from the Portal GraphQL API.
11964
+ *
11965
+ * Portal `Game.id` values are platform-game IDs, distinct from Wallet
11966
+ * global-game IDs. Never pass them to Wallet game-management mutations.
11967
+ *
11968
+ * The Portal `games` resolver does not supply `totalCount`, so the
11969
+ * result does not include it. Use `hasNextPage` and `endCursor` for
11970
+ * cursor pagination.
11971
+ *
11972
+ * For player-facing catalogs, pass `filter: { hidden: { equal: false } }`.
11973
+ *
11974
+ * Portal is eventually consistent — refetch or poll after Wallet writes.
11975
+ */
11976
+ async _games(input) {
11977
+ const res = await this.portalService._games(input);
11978
+ if (!res.ok) return res;
11979
+ return {
11980
+ ok: true,
11981
+ data: {
11982
+ _games: res.data.edges.map(({ cursor, node }) => ({
11983
+ ...node,
11984
+ cursor
11985
+ })),
11986
+ hasNextPage: res.data.pageInfo.hasNextPage,
11987
+ endCursor: res.data.pageInfo.endCursor ?? void 0
11988
+ }
11989
+ };
11990
+ }
11991
+ /**
11992
+ * Fetches all game groups for the current platform.
11993
+ *
11994
+ * Portal sorts the result by name ascending. There is no pagination.
11995
+ * An empty array is a valid result (platform with no configured groups).
11996
+ */
11997
+ async _gameGroups() {
11998
+ const res = await this.portalService._gameGroups();
11999
+ if (!res.ok) return res;
12000
+ return {
12001
+ ok: true,
12002
+ data: res.data
12003
+ };
12004
+ }
12005
+ /**
12006
+ * Fetches a single game group and its ordered games via `node(id)`.
12007
+ *
12008
+ * The returned `games` array preserves the Wallet-managed group order.
12009
+ * Missing projected platform games are filtered out by the resolver.
12010
+ * Omit `limit` and `offset` to load the whole group (Wallet caps at 100).
12011
+ *
12012
+ * Returns `{ ok: true, data: null }` when the group is missing, belongs
12013
+ * to another platform, or the platform context is invalid.
12014
+ */
12015
+ async _gameGroup(id, opts) {
12016
+ const res = await this.portalService._gameGroupNode(
12017
+ id,
12018
+ opts?.limit,
12019
+ opts?.offset
12020
+ );
12021
+ if (!res.ok) return res;
12022
+ return {
12023
+ ok: true,
12024
+ data: res.data
12025
+ };
12026
+ }
12027
+ /**
12028
+ * Fetches a single game by Portal platform-game ID via `node(id)`.
12029
+ *
12030
+ * Requires a Portal `Game.id` (platform-game ID). Passing a Wallet
12031
+ * global-game ID returns `null`.
12032
+ *
12033
+ * Includes reverse group membership via `Game.groups`. Legacy Portal
12034
+ * game rows may return an empty `groups` array — treat this as no
12035
+ * known memberships, not a request failure.
12036
+ *
12037
+ * Returns `{ ok: true, data: null }` when the game is missing, belongs
12038
+ * to another platform, or the platform context is invalid.
12039
+ */
12040
+ async _game(id) {
12041
+ const res = await this.portalService._gameNode(id);
12042
+ if (!res.ok) return res;
12043
+ return {
12044
+ ok: true,
12045
+ data: res.data
12046
+ };
12047
+ }
11814
12048
  async games__next(input) {
11815
12049
  const res = await this.cmsPortalService.games__next(input);
11816
12050
  if (!res.ok) return res;