@moneypot/hub 1.4.1 → 1.4.3

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,7 +1,22 @@
1
1
  import * as pg from "pg";
2
- import { DbCurrency, DbSession } from "./types.js";
3
- export declare function getActiveSessionById(pgClient: pg.PoolClient, sessionId: string): Promise<DbSession | undefined>;
4
- export declare function getCasinoCurrencyByKey(pgClient: pg.PoolClient, { currencyKey, casinoId }: {
2
+ import { DbBalance, DbBankroll, DbCurrency, DbSession } from "./types.js";
3
+ import { PgClientInTransaction } from "./index.js";
4
+ export declare function dbGetActiveSessionById(pgClient: pg.PoolClient, sessionId: string): Promise<DbSession | undefined>;
5
+ export declare function dbGetCasinoCurrencyByKey(pgClient: pg.PoolClient, { currencyKey, casinoId }: {
5
6
  currencyKey: string;
6
7
  casinoId: string;
7
8
  }): Promise<DbCurrency | undefined>;
9
+ export declare function dbLockPlayerBalanceAndHouseBankroll(pgClient: PgClientInTransaction, { userId, casinoId, experienceId, currencyKey, }: {
10
+ userId: string;
11
+ casinoId: string;
12
+ experienceId: string;
13
+ currencyKey: string;
14
+ }): Promise<{
15
+ found: false;
16
+ dbPlayerBalance: null;
17
+ dbHouseBankroll: null;
18
+ } | {
19
+ found: true;
20
+ dbPlayerBalance: Pick<DbBalance, "id" | "amount">;
21
+ dbHouseBankroll: Pick<DbBankroll, "id" | "amount">;
22
+ }>;
@@ -1,12 +1,13 @@
1
1
  import { maybeOneRow } from "./util.js";
2
- export async function getActiveSessionById(pgClient, sessionId) {
2
+ import { assert } from "tsafe";
3
+ export async function dbGetActiveSessionById(pgClient, sessionId) {
3
4
  return pgClient
4
5
  .query("select * from hub.active_session where id = $1", [
5
6
  sessionId,
6
7
  ])
7
8
  .then(maybeOneRow);
8
9
  }
9
- export async function getCasinoCurrencyByKey(pgClient, { currencyKey, casinoId }) {
10
+ export async function dbGetCasinoCurrencyByKey(pgClient, { currencyKey, casinoId }) {
10
11
  return pgClient
11
12
  .query({
12
13
  text: `
@@ -18,3 +19,40 @@ export async function getCasinoCurrencyByKey(pgClient, { currencyKey, casinoId }
18
19
  })
19
20
  .then(maybeOneRow);
20
21
  }
22
+ export async function dbLockPlayerBalanceAndHouseBankroll(pgClient, { userId, casinoId, experienceId, currencyKey, }) {
23
+ assert(pgClient._inTransaction, "pgClient must be in a transaction");
24
+ const row = await pgClient
25
+ .query(`
26
+ WITH locked_balance AS (
27
+ SELECT id, amount
28
+ FROM hub.balance
29
+ WHERE user_id = $1
30
+ AND casino_id = $2
31
+ AND experience_id = $3
32
+ AND currency_key = $4
33
+
34
+ FOR UPDATE
35
+ )
36
+ SELECT
37
+ json_build_object('id', pb.id, 'amount', pb.amount) as player_balance,
38
+ json_build_object('id', br.id, 'amount', br.amount) as house_bankroll
39
+ FROM locked_balance pb
40
+ JOIN hub.bankroll br
41
+ ON br.casino_id = $2
42
+ AND br.currency_key = $4
43
+
44
+ FOR UPDATE OF br
45
+ `, [userId, casinoId, experienceId, currencyKey])
46
+ .then(maybeOneRow);
47
+ return row
48
+ ? {
49
+ found: true,
50
+ dbPlayerBalance: row.player_balance,
51
+ dbHouseBankroll: row.house_bankroll,
52
+ }
53
+ : {
54
+ found: false,
55
+ dbPlayerBalance: null,
56
+ dbHouseBankroll: null,
57
+ };
58
+ }
@@ -2,7 +2,7 @@ import { access, context, object, ObjectStep, polymorphicBranch, sideEffect, } f
2
2
  import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
3
3
  import { z } from "zod";
4
4
  import { GraphQLError } from "graphql";
5
- import { DbHashKind, exactlyOneRow, maybeOneRow, superuserPool, withPgPoolTransaction, } from "../db/index.js";
5
+ import { DbHashKind, dbLockPlayerBalanceAndHouseBankroll, exactlyOneRow, maybeOneRow, superuserPool, withPgPoolTransaction, } from "../db/index.js";
6
6
  import { assert } from "tsafe";
7
7
  import { dbInsertHubHash, dbLockHubHashChain, } from "../hash-chain/db-hash-chain.js";
8
8
  import { getIntermediateHash, getPreimageHash, } from "../hash-chain/get-hash.js";
@@ -150,7 +150,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
150
150
  throw new GraphQLError("Currency not found");
151
151
  }
152
152
  return withPgPoolTransaction(superuserPool, async (pgClient) => {
153
- const { dbPlayerBalance, dbHouseBankroll, found } = await dbLockBalanceAndBankroll(pgClient, {
153
+ const { dbPlayerBalance, dbHouseBankroll, found } = await dbLockPlayerBalanceAndHouseBankroll(pgClient, {
154
154
  userId: session.user_id,
155
155
  casinoId: session.casino_id,
156
156
  experienceId: session.experience_id,
@@ -167,7 +167,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
167
167
  maxPlayerLoss,
168
168
  dbPlayerBalance,
169
169
  });
170
- if (dbPlayerBalance < maxPlayerLoss) {
170
+ if (dbPlayerBalance.amount < maxPlayerLoss) {
171
171
  if (minProfit === -1) {
172
172
  throw new GraphQLError(`You cannot afford wager`);
173
173
  }
@@ -175,7 +175,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
175
175
  }
176
176
  const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
177
177
  const maxPotentialPayout = input.wager * maxProfitMultiplier;
178
- const maxAllowablePayout = dbHouseBankroll * 0.01;
178
+ const maxAllowablePayout = dbHouseBankroll.amount * 0.01;
179
179
  if (maxPotentialPayout > maxAllowablePayout) {
180
180
  throw new GraphQLError(`House risk limit exceeded. Max payout: ${maxPotentialPayout.toFixed(4)}`);
181
181
  }
@@ -409,43 +409,6 @@ function pickRandomOutcome({ outcomes, hash, }) {
409
409
  outcomeIdx: outcomes.length - 1,
410
410
  };
411
411
  }
412
- async function dbLockBalanceAndBankroll(pgClient, { userId, casinoId, experienceId, currencyKey, }) {
413
- assert(pgClient._inTransaction, "pgClient must be in a transaction");
414
- const row = await pgClient
415
- .query(`
416
- WITH locked_balance AS (
417
- SELECT amount
418
- FROM hub.balance
419
- WHERE user_id = $1
420
- AND casino_id = $2
421
- AND experience_id = $3
422
- AND currency_key = $4
423
-
424
- FOR UPDATE
425
- )
426
- SELECT
427
- pb.amount as player_balance,
428
- br.amount as house_bankroll
429
- FROM locked_balance pb
430
- JOIN hub.bankroll br
431
- ON br.casino_id = $2
432
- AND br.currency_key = $4
433
-
434
- FOR UPDATE OF br
435
- `, [userId, casinoId, experienceId, currencyKey])
436
- .then(maybeOneRow);
437
- return row
438
- ? {
439
- found: true,
440
- dbPlayerBalance: row.player_balance,
441
- dbHouseBankroll: row.house_bankroll,
442
- }
443
- : {
444
- found: false,
445
- dbPlayerBalance: null,
446
- dbHouseBankroll: null,
447
- };
448
- }
449
412
  async function finishHashChainInBackground({ hashChainId, }) {
450
413
  console.log("Finishing hash chain in background", { hashChainId });
451
414
  const preimageHashResult = await getPreimageHash({
@@ -29,6 +29,10 @@ export const HubPutAlertPlugin = makeExtendSchemaPlugin(() => {
29
29
  }
30
30
  });
31
31
  return listenWithFilter($pgSubscriber, $channelKey, jsonParse, $identity, (item, identity) => {
32
+ if (typeof item !== "string") {
33
+ console.warn(`hubPutAlert: item is not a string: ${JSON.stringify(item)}`);
34
+ return false;
35
+ }
32
36
  if (identity?.kind !== "user") {
33
37
  return false;
34
38
  }
@@ -5,7 +5,7 @@ export declare class ListenWithFilterStep<TTopics extends {
5
5
  [topic: string]: any;
6
6
  }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput> extends Step<TTopics[TTopic][]> {
7
7
  itemPlan: (itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep;
8
- filterFn: (item: any, filterInput: TFilterInput) => boolean;
8
+ filterFn: (item: unknown, filterInput: TFilterInput) => boolean;
9
9
  static $$export: {
10
10
  moduleName: string;
11
11
  exportName: string;
@@ -14,9 +14,9 @@ export declare class ListenWithFilterStep<TTopics extends {
14
14
  private pubsubDep;
15
15
  private topicDep;
16
16
  private filterInputDep;
17
- constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: any, filterInput: TFilterInput) => boolean);
17
+ constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean);
18
18
  execute({ indexMap, values, stream, }: ExecutionDetails<readonly [GrafastSubscriber<TTopics>, TTopic]>): GrafastResultStreamList<TTopics[TTopic]>;
19
19
  }
20
20
  export declare function listenWithFilter<TTopics extends {
21
21
  [topic: string]: any;
22
- }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: any, filterInput: TFilterInput) => boolean): ListenWithFilterStep<TTopics, TTopic, TPayloadStep, TFilterInput>;
22
+ }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean): ListenWithFilterStep<TTopics, TTopic, TPayloadStep, TFilterInput>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [