@moneypot/hub 1.14.7 → 1.15.0-dev.1
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/dashboard/assets/{index-BXG4SGJn.js → index-CrY0xaa9.js} +35 -34
- package/dist/dashboard/index.html +1 -1
- package/dist/src/db/index.d.ts +4 -1
- package/dist/src/db/index.js +6 -4
- package/dist/src/db/types.d.ts +1 -0
- package/dist/src/express.d.ts +1 -0
- package/dist/src/pg-versions/001-schema.sql +1 -0
- package/dist/src/pg-versions/012-playground.sql +40 -0
- package/dist/src/plugins/hub-authenticate.js +15 -10
- package/dist/src/plugins/hub-create-playground-session.d.ts +1 -0
- package/dist/src/plugins/hub-create-playground-session.js +181 -0
- package/dist/src/plugins/hub-make-outcome-bet.js +6 -1
- package/dist/src/plugins/hub-withdraw.js +19 -7
- package/dist/src/process-transfers/index.js +3 -2
- package/dist/src/server/graphile.config.d.ts +1 -0
- package/dist/src/server/graphile.config.js +4 -0
- package/dist/src/server/middleware/authentication.js +1 -0
- package/dist/src/smart-tags.js +5 -0
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Dashboard</title>
|
|
7
|
-
<script type="module" crossorigin src="/dashboard/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/dashboard/assets/index-CrY0xaa9.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/dashboard/assets/index-LZVcTrKv.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/dist/src/db/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare function withPgPoolTransaction<T>(pool: pg.Pool, callback: (_pgCl
|
|
|
20
20
|
export declare function userFromActiveSessionKey(pgClient: QueryExecutor, sessionKey: string): Promise<{
|
|
21
21
|
user: DbUser;
|
|
22
22
|
sessionId: DbSession["id"];
|
|
23
|
+
isPlayground: boolean;
|
|
23
24
|
} | null>;
|
|
24
25
|
export declare class DatabaseNotifier extends stream.EventEmitter {
|
|
25
26
|
private pgClient;
|
|
@@ -79,7 +80,9 @@ export declare function settleWithdrawal(pool: pg.Pool, { withdrawalId, newStatu
|
|
|
79
80
|
withdrawalId: string;
|
|
80
81
|
newStatus: Extract<DbTransferStatusKind, "COMPLETED" | "CANCELED">;
|
|
81
82
|
}): Promise<void>;
|
|
82
|
-
export declare function listCasinos(pgClient: QueryExecutor
|
|
83
|
+
export declare function listCasinos(pgClient: QueryExecutor, { isPlayground }: {
|
|
84
|
+
isPlayground: "include" | "exclude";
|
|
85
|
+
}): Promise<DbCasino[]>;
|
|
83
86
|
export declare function upsertCurrencies(pgClient: QueryExecutor, { casinoId, currencies, }: {
|
|
84
87
|
casinoId: string;
|
|
85
88
|
currencies: {
|
package/dist/src/db/index.js
CHANGED
|
@@ -71,20 +71,22 @@ export async function withPgPoolTransaction(pool, callback, retryCount = 0, maxR
|
|
|
71
71
|
export async function userFromActiveSessionKey(pgClient, sessionKey) {
|
|
72
72
|
const result = await pgClient
|
|
73
73
|
.query(`
|
|
74
|
-
select u.id, u.uname, u.casino_id, s.experience_id, u.mp_user_id, s.id as session_id
|
|
74
|
+
select u.id, u.uname, u.casino_id, s.experience_id, u.mp_user_id, s.id as session_id, c.is_playground
|
|
75
75
|
from hub.active_session s
|
|
76
76
|
join hub.user u on s.user_id = u.id
|
|
77
77
|
join hub.experience e on e.id = s.experience_id
|
|
78
|
+
join hub.casino c on c.id = u.casino_id
|
|
78
79
|
where s.key = $1
|
|
79
80
|
`, [sessionKey])
|
|
80
81
|
.then(maybeOneRow);
|
|
81
82
|
if (!result) {
|
|
82
83
|
return null;
|
|
83
84
|
}
|
|
84
|
-
const { session_id, ...user } = result;
|
|
85
|
+
const { session_id, is_playground, ...user } = result;
|
|
85
86
|
return {
|
|
86
87
|
user,
|
|
87
88
|
sessionId: session_id,
|
|
89
|
+
isPlayground: is_playground,
|
|
88
90
|
};
|
|
89
91
|
}
|
|
90
92
|
export class DatabaseNotifier extends stream.EventEmitter {
|
|
@@ -339,8 +341,8 @@ export async function settleWithdrawal(pool, { withdrawalId, newStatus, }) {
|
|
|
339
341
|
}
|
|
340
342
|
});
|
|
341
343
|
}
|
|
342
|
-
export async function listCasinos(pgClient) {
|
|
343
|
-
const result = await pgClient.query(
|
|
344
|
+
export async function listCasinos(pgClient, { isPlayground }) {
|
|
345
|
+
const result = await pgClient.query(`select * from hub.casino ${isPlayground === "include" ? "" : "where not is_playground"}`);
|
|
344
346
|
return result.rows;
|
|
345
347
|
}
|
|
346
348
|
export async function upsertCurrencies(pgClient, { casinoId, currencies, }) {
|
package/dist/src/db/types.d.ts
CHANGED
package/dist/src/express.d.ts
CHANGED
|
@@ -182,6 +182,7 @@ create table hub.session (
|
|
|
182
182
|
CREATE INDEX session_casino_id_idx ON hub.session(casino_id);
|
|
183
183
|
CREATE INDEX session_user_id_idx ON hub.session(user_id);
|
|
184
184
|
CREATE INDEX session_experience_id_idx ON hub.session(experience_id);
|
|
185
|
+
-- TODO: Shouldn't these only be unique per casino/exp?
|
|
185
186
|
CREATE UNIQUE INDEX session_user_token_idx ON hub.session(user_token);
|
|
186
187
|
CREATE UNIQUE INDEX session_key_idx ON hub.session(key);
|
|
187
188
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- insert a global playground app.casino record that all playground users and experiences are associated with
|
|
2
|
+
|
|
3
|
+
-- add is_playground boolean to the casino table with default=false for existing casinos
|
|
4
|
+
alter table hub.casino add column is_playground boolean not null default false;
|
|
5
|
+
|
|
6
|
+
insert into hub.casino (name, base_url, graphql_url, is_playground)
|
|
7
|
+
values (
|
|
8
|
+
'Playground',
|
|
9
|
+
'https://not-found.moneypot.com',
|
|
10
|
+
'https://not-found.moneypot.com/graphql',
|
|
11
|
+
true
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
-- make it so that only one row can have is_playground=true and the rest are false
|
|
15
|
+
CREATE UNIQUE INDEX single_playground_casino_idx
|
|
16
|
+
ON hub.casino ((true))
|
|
17
|
+
WHERE is_playground;
|
|
18
|
+
|
|
19
|
+
-- insert HOUSE hub.currency for casino
|
|
20
|
+
insert into hub.currency (key, casino_id, display_unit_name, display_unit_scale)
|
|
21
|
+
select 'HOUSE', (select id from hub.casino where is_playground = true limit 1), 'token', 1;
|
|
22
|
+
|
|
23
|
+
-- insert 10_000_000 HOUSE bankroll for casino
|
|
24
|
+
insert into hub.bankroll (casino_id, currency_key, amount)
|
|
25
|
+
select (select id from hub.casino where is_playground = true limit 1), 'HOUSE', 10_000_000;
|
|
26
|
+
|
|
27
|
+
-- Update the notify_new_casino trigger function to exclude playground casinos
|
|
28
|
+
-- TODO: Seems weird that this even is a trigger... oh well, just porting it for now
|
|
29
|
+
CREATE OR REPLACE FUNCTION notify_new_casino()
|
|
30
|
+
RETURNS TRIGGER AS $$
|
|
31
|
+
BEGIN
|
|
32
|
+
-- Only notify for non-playground casinos
|
|
33
|
+
IF NEW.is_playground = false THEN
|
|
34
|
+
PERFORM pg_notify('hub:new_casino', json_build_object(
|
|
35
|
+
'id', NEW.id
|
|
36
|
+
)::text);
|
|
37
|
+
END IF;
|
|
38
|
+
RETURN NEW;
|
|
39
|
+
END;
|
|
40
|
+
$$ LANGUAGE plpgsql;
|
|
@@ -10,6 +10,7 @@ import { logger } from "../logger.js";
|
|
|
10
10
|
import * as jwtService from "../services/jwt-service.js";
|
|
11
11
|
import { extractGraphQLErrorInfo, isGraphQLError } from "../GraphQLError.js";
|
|
12
12
|
import { z } from "zod";
|
|
13
|
+
import { prettifyError } from "zod/v4";
|
|
13
14
|
const BaseUrlSchema = z
|
|
14
15
|
.string()
|
|
15
16
|
.refine((val) => URL.canParse(val), "Base URL must be a valid url")
|
|
@@ -53,17 +54,17 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
53
54
|
const $context = context();
|
|
54
55
|
const $superuserPool = $context.get("superuserPool");
|
|
55
56
|
const $success = sideEffect([$input, $superuserPool, $context], ([rawInput, superuserPool, context]) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
throw new GraphQLError(e.errors[0].message);
|
|
64
|
-
}
|
|
65
|
-
throw e;
|
|
57
|
+
let input;
|
|
58
|
+
try {
|
|
59
|
+
input = InputSchema.parse(rawInput);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
if (e instanceof z.ZodError) {
|
|
63
|
+
throw new GraphQLError(prettifyError(e));
|
|
66
64
|
}
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
67
68
|
const { userToken: jwt, casinoBaseUrl } = input;
|
|
68
69
|
const casino = await pgClient
|
|
69
70
|
.query({
|
|
@@ -78,6 +79,9 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
78
79
|
if (!casino) {
|
|
79
80
|
throw new GraphQLError(`hub server is unaware of casino with a base url of provided casinoBaseUrl`);
|
|
80
81
|
}
|
|
82
|
+
if (casino.is_playground) {
|
|
83
|
+
throw new GraphQLError("Cannot authenticate with playground casino");
|
|
84
|
+
}
|
|
81
85
|
if (!casino.api_key) {
|
|
82
86
|
throw new GraphQLError("Casino secret not configured");
|
|
83
87
|
}
|
|
@@ -180,6 +184,7 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
180
184
|
casino_id: casino.id,
|
|
181
185
|
experience_id: dbExperience.id,
|
|
182
186
|
session_id: dbSession.id,
|
|
187
|
+
is_playground: false,
|
|
183
188
|
},
|
|
184
189
|
};
|
|
185
190
|
context.pgSettings = {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubCreatePlaygroundSessionPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
4
|
+
import { constant, context, object, sideEffect } from "postgraphile/grafast";
|
|
5
|
+
import { withPgPoolTransaction, } from "../db/index.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { prettifyError } from "zod/v4";
|
|
9
|
+
const InputSchema = z.object({
|
|
10
|
+
dummy: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
export const HubCreatePlaygroundSessionPlugin = makeExtendSchemaPlugin(() => {
|
|
13
|
+
return {
|
|
14
|
+
typeDefs: gql `
|
|
15
|
+
input HubCreatePlaygroundSessionInput {
|
|
16
|
+
dummy: String
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
extend type Mutation {
|
|
20
|
+
hubCreatePlaygroundSession(
|
|
21
|
+
input: HubCreatePlaygroundSessionInput!
|
|
22
|
+
): HubAuthenticatePayload
|
|
23
|
+
}
|
|
24
|
+
`,
|
|
25
|
+
objects: {
|
|
26
|
+
Mutation: {
|
|
27
|
+
plans: {
|
|
28
|
+
hubCreatePlaygroundSession(_, { $input }) {
|
|
29
|
+
try {
|
|
30
|
+
const $context = context();
|
|
31
|
+
const $superuserPool = $context.get("superuserPool");
|
|
32
|
+
const $success = sideEffect([$input, $superuserPool, $context], ([rawInput, superuserPool, context]) => {
|
|
33
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
34
|
+
let _input;
|
|
35
|
+
try {
|
|
36
|
+
_input = InputSchema.parse(rawInput);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
if (e instanceof z.ZodError) {
|
|
40
|
+
throw new GraphQLError(prettifyError(e));
|
|
41
|
+
}
|
|
42
|
+
throw e;
|
|
43
|
+
}
|
|
44
|
+
const dbPlaygroundCasino = await pgClient
|
|
45
|
+
.query({
|
|
46
|
+
text: `
|
|
47
|
+
SELECT c.*
|
|
48
|
+
FROM hub.casino c
|
|
49
|
+
WHERE c.is_playground = true
|
|
50
|
+
LIMIT 1
|
|
51
|
+
`,
|
|
52
|
+
values: [],
|
|
53
|
+
})
|
|
54
|
+
.then(maybeOneRow);
|
|
55
|
+
if (!dbPlaygroundCasino) {
|
|
56
|
+
throw new GraphQLError("No playground casino found");
|
|
57
|
+
}
|
|
58
|
+
const DUMMY_MP_ID = uuidv7();
|
|
59
|
+
const randomUname = createRandomUname();
|
|
60
|
+
const dbUser = await pgClient
|
|
61
|
+
.query({
|
|
62
|
+
text: `
|
|
63
|
+
INSERT INTO hub.user(casino_id, mp_user_id, uname)
|
|
64
|
+
VALUES($1, $2, $3)
|
|
65
|
+
RETURNING id, uname, mp_user_id
|
|
66
|
+
`,
|
|
67
|
+
values: [
|
|
68
|
+
dbPlaygroundCasino.id,
|
|
69
|
+
DUMMY_MP_ID,
|
|
70
|
+
randomUname,
|
|
71
|
+
],
|
|
72
|
+
})
|
|
73
|
+
.then(exactlyOneRow);
|
|
74
|
+
const dbExperience = await pgClient
|
|
75
|
+
.query({
|
|
76
|
+
text: `
|
|
77
|
+
INSERT INTO hub.experience(casino_id, mp_experience_id, name)
|
|
78
|
+
VALUES($1, $2, $3)
|
|
79
|
+
RETURNING id
|
|
80
|
+
`,
|
|
81
|
+
values: [
|
|
82
|
+
dbPlaygroundCasino.id,
|
|
83
|
+
DUMMY_MP_ID,
|
|
84
|
+
`Playground Experience ${randomUname}`,
|
|
85
|
+
],
|
|
86
|
+
})
|
|
87
|
+
.then(exactlyOneRow);
|
|
88
|
+
await pgClient.query({
|
|
89
|
+
text: `
|
|
90
|
+
INSERT INTO hub.balance(user_id, experience_id, casino_id, currency_key, amount)
|
|
91
|
+
VALUES($1, $2, $3, $4, 1000)
|
|
92
|
+
`,
|
|
93
|
+
values: [
|
|
94
|
+
dbUser.id,
|
|
95
|
+
dbExperience.id,
|
|
96
|
+
dbPlaygroundCasino.id,
|
|
97
|
+
"HOUSE",
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
const dbSession = await pgClient
|
|
101
|
+
.query({
|
|
102
|
+
text: `
|
|
103
|
+
INSERT INTO hub.session(casino_id, user_id, experience_id, user_token)
|
|
104
|
+
VALUES($1, $2, $3, $4)
|
|
105
|
+
RETURNING id, key
|
|
106
|
+
`,
|
|
107
|
+
values: [
|
|
108
|
+
dbPlaygroundCasino.id,
|
|
109
|
+
dbUser.id,
|
|
110
|
+
dbExperience.id,
|
|
111
|
+
DUMMY_MP_ID,
|
|
112
|
+
],
|
|
113
|
+
})
|
|
114
|
+
.then(exactlyOneRow);
|
|
115
|
+
const ret = {
|
|
116
|
+
userId: dbUser.id,
|
|
117
|
+
uname: dbUser.uname,
|
|
118
|
+
experienceId: dbExperience.id,
|
|
119
|
+
sessionKey: dbSession.key,
|
|
120
|
+
};
|
|
121
|
+
context.identity = {
|
|
122
|
+
kind: "user",
|
|
123
|
+
session: {
|
|
124
|
+
user_id: dbUser.id,
|
|
125
|
+
mp_user_id: dbUser.mp_user_id,
|
|
126
|
+
casino_id: dbPlaygroundCasino.id,
|
|
127
|
+
experience_id: dbExperience.id,
|
|
128
|
+
session_id: dbSession.id,
|
|
129
|
+
is_playground: true,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
context.pgSettings = {
|
|
133
|
+
"session.user_id": dbUser.id,
|
|
134
|
+
"session.casino_id": dbPlaygroundCasino.id,
|
|
135
|
+
"session.experience_id": dbExperience.id,
|
|
136
|
+
"session.session_id": dbSession.id,
|
|
137
|
+
};
|
|
138
|
+
return ret;
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
return object({
|
|
142
|
+
query: constant(true),
|
|
143
|
+
success: $success,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
logger.error(error);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
function uuidv7() {
|
|
157
|
+
const now = BigInt(Date.now());
|
|
158
|
+
let timestamp = now & ((1n << 48n) - 1n);
|
|
159
|
+
const rand = crypto.getRandomValues(new Uint8Array(10));
|
|
160
|
+
const bytes = new Uint8Array(16);
|
|
161
|
+
for (let i = 5; i >= 0; i--) {
|
|
162
|
+
bytes[i] = Number(timestamp & 0xffn);
|
|
163
|
+
timestamp >>= 8n;
|
|
164
|
+
}
|
|
165
|
+
bytes.set(rand, 6);
|
|
166
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x70;
|
|
167
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
168
|
+
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
169
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
170
|
+
}
|
|
171
|
+
function createRandomUname() {
|
|
172
|
+
const MAX_MP_UNAME_LENGTH = 15;
|
|
173
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
174
|
+
let result = "play_";
|
|
175
|
+
const SUFFIX_LENGTH = MAX_MP_UNAME_LENGTH - result.length;
|
|
176
|
+
for (let i = 0; i < SUFFIX_LENGTH; i++) {
|
|
177
|
+
const idx = Math.floor(Math.random() * chars.length);
|
|
178
|
+
result += chars[idx];
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
@@ -11,6 +11,7 @@ import { logger } from "../logger.js";
|
|
|
11
11
|
import { validateRisk } from "../risk-policy.js";
|
|
12
12
|
import { insertAuditLog } from "../audit-log.js";
|
|
13
13
|
import { dbRevealHashChain } from "../hash-chain/reveal-hash-chain.js";
|
|
14
|
+
import { prettifyError } from "zod/v4";
|
|
14
15
|
const FLOAT_EPSILON = 1e-10;
|
|
15
16
|
function sum(ns) {
|
|
16
17
|
return ns.reduce((a, b) => a + b, 0);
|
|
@@ -121,10 +122,14 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
121
122
|
}
|
|
122
123
|
catch (e) {
|
|
123
124
|
if (e instanceof z.ZodError) {
|
|
124
|
-
throw new GraphQLError(e
|
|
125
|
+
throw new GraphQLError(prettifyError(e));
|
|
125
126
|
}
|
|
126
127
|
throw e;
|
|
127
128
|
}
|
|
129
|
+
if (identity.session.is_playground &&
|
|
130
|
+
input.currency !== "HOUSE") {
|
|
131
|
+
throw new GraphQLError("Playground users can only bet with HOUSE currency");
|
|
132
|
+
}
|
|
128
133
|
const betConfig = betConfigs[betKind];
|
|
129
134
|
if (!betConfig) {
|
|
130
135
|
throw new GraphQLError(`Invalid bet kind`);
|
|
@@ -3,6 +3,11 @@ import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
|
3
3
|
import { withPgPoolTransaction } from "../db/index.js";
|
|
4
4
|
import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
5
5
|
import { GraphQLError } from "graphql";
|
|
6
|
+
import z, { prettifyError } from "zod/v4";
|
|
7
|
+
const InputSchema = z.object({
|
|
8
|
+
amount: z.number().min(1),
|
|
9
|
+
currency: z.string(),
|
|
10
|
+
});
|
|
6
11
|
export const HubWithdrawPlugin = makeExtendSchemaPlugin((build) => {
|
|
7
12
|
const hubWithdrawalRequests = build.input.pgRegistry.pgResources.hub_withdrawal_request;
|
|
8
13
|
return {
|
|
@@ -27,19 +32,26 @@ export const HubWithdrawPlugin = makeExtendSchemaPlugin((build) => {
|
|
|
27
32
|
hubWithdraw(_, { $input }) {
|
|
28
33
|
const $identity = context().get("identity");
|
|
29
34
|
const $superuserPool = context().get("superuserPool");
|
|
30
|
-
const $withdrawalRequestId = sideEffect([$input, $identity, $superuserPool], ([
|
|
35
|
+
const $withdrawalRequestId = sideEffect([$input, $identity, $superuserPool], ([rawInput, identity, superuserPool]) => {
|
|
31
36
|
if (identity?.kind !== "user") {
|
|
32
37
|
throw new GraphQLError("You must be logged in");
|
|
33
38
|
}
|
|
39
|
+
if (identity.session.is_playground) {
|
|
40
|
+
throw new GraphQLError("Playground users cannot withdraw");
|
|
41
|
+
}
|
|
42
|
+
let input;
|
|
43
|
+
try {
|
|
44
|
+
input = InputSchema.parse(rawInput);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
if (e instanceof z.ZodError) {
|
|
48
|
+
throw new GraphQLError(prettifyError(e));
|
|
49
|
+
}
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
34
52
|
const { session } = identity;
|
|
35
53
|
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
36
54
|
const { amount, currency } = input;
|
|
37
|
-
if (amount < 1) {
|
|
38
|
-
throw new GraphQLError("Withdraw amount must be at least 1");
|
|
39
|
-
}
|
|
40
|
-
if (!Number.isInteger(amount)) {
|
|
41
|
-
throw new GraphQLError("Withdraw amount must be an integer");
|
|
42
|
-
}
|
|
43
55
|
const dbCurrency = await pgClient
|
|
44
56
|
.query({
|
|
45
57
|
text: `
|
|
@@ -13,8 +13,9 @@ export async function startCasinoTransferProcessor({ casinoId, signal, pool, })
|
|
|
13
13
|
throw new Error(`processor already running for casino ${casinoId}`);
|
|
14
14
|
}
|
|
15
15
|
const casino = await dbGetCasinoById(pool, casinoId);
|
|
16
|
-
const secret = await dbGetCasinoSecretById(pool, casinoId);
|
|
17
16
|
assert(casino, `Casino not found for casino id ${casinoId}`);
|
|
17
|
+
assert(!casino.is_playground, `Cannot start processor for playground casino ${casinoId}`);
|
|
18
|
+
const secret = await dbGetCasinoSecretById(pool, casinoId);
|
|
18
19
|
assert(secret, `Secret not found for casino id ${casinoId}`);
|
|
19
20
|
activeCasinos.add(casinoId);
|
|
20
21
|
startPollingProcessor({ casinoId, signal, pool });
|
|
@@ -30,7 +31,7 @@ export async function startCasinoTransferProcessor({ casinoId, signal, pool, })
|
|
|
30
31
|
export function initializeTransferProcessors({ signal, pool, }) {
|
|
31
32
|
(async () => {
|
|
32
33
|
try {
|
|
33
|
-
const casinos = await db.listCasinos(pool);
|
|
34
|
+
const casinos = await db.listCasinos(pool, { isPlayground: "exclude" });
|
|
34
35
|
for (const casino of casinos) {
|
|
35
36
|
if (!URL.canParse(casino.graphql_url)) {
|
|
36
37
|
logger.warn(`Skipping casino ${casino.id} due to invalid graphql_url: "${casino.graphql_url}"`);
|
|
@@ -25,11 +25,13 @@ import { HubOutcomeInputNonNullFieldsPlugin } from "../plugins/hub-outcome-input
|
|
|
25
25
|
import { HubPutAlertPlugin } from "../plugins/hub-put-alert.js";
|
|
26
26
|
import { HubRevealHashChainPlugin } from "../hash-chain/plugins/hub-reveal-hash-chain.js";
|
|
27
27
|
import { HubPreimageHashFieldPlugin } from "../hash-chain/plugins/hub-preimage-hash-field.js";
|
|
28
|
+
import { HubCreatePlaygroundSessionPlugin } from "../plugins/hub-create-playground-session.js";
|
|
28
29
|
export const requiredPlugins = [
|
|
29
30
|
SmartTagsPlugin,
|
|
30
31
|
IdToNodeIdPlugin,
|
|
31
32
|
HubPrefixPlugin,
|
|
32
33
|
HubAuthenticatePlugin,
|
|
34
|
+
HubCreatePlaygroundSessionPlugin,
|
|
33
35
|
HubCurrentXPlugin,
|
|
34
36
|
HubBalanceAlertPlugin,
|
|
35
37
|
HubPutAlertPlugin,
|
|
@@ -115,6 +117,7 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
115
117
|
casino_id: reqIdentity.user.casino_id,
|
|
116
118
|
experience_id: reqIdentity.user.experience_id,
|
|
117
119
|
session_id: reqIdentity.sessionId,
|
|
120
|
+
is_playground: reqIdentity.isPlayground,
|
|
118
121
|
},
|
|
119
122
|
};
|
|
120
123
|
}
|
|
@@ -163,6 +166,7 @@ async function handleWebsocketContext(context, ws) {
|
|
|
163
166
|
casino_id: result.user.casino_id,
|
|
164
167
|
experience_id: result.user.experience_id,
|
|
165
168
|
session_id: result.sessionId,
|
|
169
|
+
is_playground: result.isPlayground,
|
|
166
170
|
};
|
|
167
171
|
return {
|
|
168
172
|
pgSettings: {
|
package/dist/src/smart-tags.js
CHANGED
|
@@ -8,6 +8,11 @@ export const SmartTagsPlugin = makeJSONPgSmartTagsPlugin({
|
|
|
8
8
|
behavior: ["-attribute:update"],
|
|
9
9
|
},
|
|
10
10
|
},
|
|
11
|
+
"hub.casino.is_playground": {
|
|
12
|
+
tags: {
|
|
13
|
+
behavior: ["-attribute:update"],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
11
16
|
"hub.session.user_token": {
|
|
12
17
|
tags: {
|
|
13
18
|
behavior: ["-orderBy"],
|