@moneypot/hub 1.15.0 → 1.16.0-dev.4
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/src/__generated__/gql.d.ts +2 -2
- package/dist/src/__generated__/gql.js +1 -1
- package/dist/src/__generated__/graphql.d.ts +240 -27
- package/dist/src/__generated__/graphql.js +30 -1
- package/dist/src/db/index.d.ts +1 -0
- package/dist/src/db/index.js +10 -2
- package/dist/src/db/public.d.ts +6 -10
- package/dist/src/db/public.js +24 -36
- package/dist/src/db/types.d.ts +24 -0
- package/dist/src/express.d.ts +1 -0
- package/dist/src/graphql-queries.js +4 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/dist/src/pg-advisory-lock.d.ts +5 -0
- package/dist/src/pg-advisory-lock.js +5 -0
- package/dist/src/pg-versions/013-chat.sql +221 -0
- package/dist/src/plugins/chat/hub-chat-after-id-condition.d.ts +1 -0
- package/dist/src/plugins/chat/hub-chat-after-id-condition.js +15 -0
- package/dist/src/plugins/chat/hub-chat-create-system-message.d.ts +1 -0
- package/dist/src/plugins/chat/hub-chat-create-system-message.js +124 -0
- package/dist/src/plugins/chat/hub-chat-create-user-message.d.ts +1 -0
- package/dist/src/plugins/chat/hub-chat-create-user-message.js +231 -0
- package/dist/src/plugins/chat/hub-chat-mute-user.d.ts +1 -0
- package/dist/src/plugins/chat/hub-chat-mute-user.js +186 -0
- package/dist/src/plugins/chat/hub-chat-subscription.d.ts +14 -0
- package/dist/src/plugins/chat/hub-chat-subscription.js +133 -0
- package/dist/src/plugins/chat/hub-chat-unmute-user.d.ts +1 -0
- package/dist/src/plugins/chat/hub-chat-unmute-user.js +146 -0
- package/dist/src/plugins/hub-authenticate.js +38 -17
- package/dist/src/plugins/hub-create-playground-session.js +44 -13
- package/dist/src/plugins/hub-make-outcome-bet.js +39 -33
- package/dist/src/server/graphile.config.d.ts +13 -1
- package/dist/src/server/graphile.config.js +38 -12
- package/dist/src/server/index.d.ts +3 -1
- package/dist/src/server/index.js +3 -1
- package/dist/src/server/middleware/authentication.js +1 -0
- package/dist/src/util.d.ts +3 -0
- package/dist/src/util.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { extendSchema, gql } from "postgraphile/utils";
|
|
2
|
+
import { context, inhibitOnNull, sideEffect } from "../../grafast.js";
|
|
3
|
+
import { GraphQLError } from "graphql";
|
|
4
|
+
import z, { object } from "zod/v4";
|
|
5
|
+
import { extractFirstZodErrorMessage } from "../../util.js";
|
|
6
|
+
import { maybeOneRow, withPgPoolTransaction, } from "../../db/index.js";
|
|
7
|
+
import { PgAdvisoryLock } from "../../pg-advisory-lock.js";
|
|
8
|
+
import { logger } from "../../logger.js";
|
|
9
|
+
const InputSchema = z.object({
|
|
10
|
+
userId: z.uuid("Invalid user ID"),
|
|
11
|
+
});
|
|
12
|
+
export const HubChatUnmuteUserPlugin = extendSchema((build) => {
|
|
13
|
+
const chatMuteTable = build.input.pgRegistry.pgResources.hub_chat_mute;
|
|
14
|
+
return {
|
|
15
|
+
typeDefs: gql `
|
|
16
|
+
input HubChatUnmuteUserInput {
|
|
17
|
+
userId: UUID!
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type HubChatUnmuteUserPayload {
|
|
21
|
+
chatMute: HubChatMute!
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
extend type Mutation {
|
|
25
|
+
hubChatUnmuteUser(
|
|
26
|
+
input: HubChatUnmuteUserInput!
|
|
27
|
+
): HubChatUnmuteUserPayload
|
|
28
|
+
}
|
|
29
|
+
`,
|
|
30
|
+
objects: {
|
|
31
|
+
Mutation: {
|
|
32
|
+
plans: {
|
|
33
|
+
hubChatUnmuteUser(_, { $input }) {
|
|
34
|
+
const $identity = context().get("identity");
|
|
35
|
+
const $superuserPool = context().get("superuserPool");
|
|
36
|
+
const $muteId = sideEffect([$input, $identity, $superuserPool], async ([rawInput, identity, superuserPool]) => {
|
|
37
|
+
if (identity?.kind !== "user") {
|
|
38
|
+
throw new GraphQLError("Unauthorized");
|
|
39
|
+
}
|
|
40
|
+
let input;
|
|
41
|
+
try {
|
|
42
|
+
input = InputSchema.parse(rawInput);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof z.ZodError) {
|
|
46
|
+
throw new GraphQLError(extractFirstZodErrorMessage(e));
|
|
47
|
+
}
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
const currentUserIsChatMod = await superuserPool
|
|
51
|
+
.query({
|
|
52
|
+
text: `
|
|
53
|
+
SELECT id, user_id
|
|
54
|
+
FROM hub.chat_mod
|
|
55
|
+
WHERE casino_id = $1 AND experience_id = $2 AND user_id = $3
|
|
56
|
+
`,
|
|
57
|
+
values: [
|
|
58
|
+
identity.session.casino_id,
|
|
59
|
+
identity.session.experience_id,
|
|
60
|
+
identity.session.user_id,
|
|
61
|
+
],
|
|
62
|
+
})
|
|
63
|
+
.then(maybeOneRow);
|
|
64
|
+
if (!identity.session.is_experience_owner &&
|
|
65
|
+
!currentUserIsChatMod) {
|
|
66
|
+
throw new GraphQLError("Unauthorized");
|
|
67
|
+
}
|
|
68
|
+
const dbTargetUser = await superuserPool
|
|
69
|
+
.query({
|
|
70
|
+
text: `
|
|
71
|
+
SELECT id
|
|
72
|
+
FROM hub.user
|
|
73
|
+
WHERE casino_id = $1 AND id = $2
|
|
74
|
+
`,
|
|
75
|
+
values: [identity.session.casino_id, input.userId],
|
|
76
|
+
})
|
|
77
|
+
.then(maybeOneRow);
|
|
78
|
+
if (!dbTargetUser) {
|
|
79
|
+
throw new GraphQLError("User not found");
|
|
80
|
+
}
|
|
81
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
82
|
+
await PgAdvisoryLock.forChatUserAction(pgClient, {
|
|
83
|
+
userId: dbTargetUser.id,
|
|
84
|
+
experienceId: identity.session.experience_id,
|
|
85
|
+
casinoId: identity.session.casino_id,
|
|
86
|
+
});
|
|
87
|
+
const dbActiveMute = await pgClient
|
|
88
|
+
.query({
|
|
89
|
+
text: `
|
|
90
|
+
SELECT id
|
|
91
|
+
FROM hub.active_chat_mute
|
|
92
|
+
WHERE user_id = $1 AND experience_id = $2 AND casino_id = $3
|
|
93
|
+
`,
|
|
94
|
+
values: [
|
|
95
|
+
dbTargetUser.id,
|
|
96
|
+
identity.session.experience_id,
|
|
97
|
+
identity.session.casino_id,
|
|
98
|
+
],
|
|
99
|
+
})
|
|
100
|
+
.then(maybeOneRow);
|
|
101
|
+
if (!dbActiveMute) {
|
|
102
|
+
throw new GraphQLError("User is not muted");
|
|
103
|
+
}
|
|
104
|
+
await pgClient
|
|
105
|
+
.query({
|
|
106
|
+
text: `
|
|
107
|
+
UPDATE hub.chat_mute
|
|
108
|
+
SET revoked_at = now()
|
|
109
|
+
WHERE user_id = $1
|
|
110
|
+
AND experience_id = $2
|
|
111
|
+
AND casino_id = $3
|
|
112
|
+
AND revoked_at IS NULL
|
|
113
|
+
`,
|
|
114
|
+
values: [
|
|
115
|
+
dbTargetUser.id,
|
|
116
|
+
identity.session.experience_id,
|
|
117
|
+
identity.session.casino_id,
|
|
118
|
+
],
|
|
119
|
+
})
|
|
120
|
+
.then((res) => {
|
|
121
|
+
if (res.rowCount !== 1) {
|
|
122
|
+
logger.warn("Expected 1 chat_mute row to be revoked when unmuting user, got %s", res.rowCount);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const notifyPayload = {
|
|
126
|
+
type: "unmute",
|
|
127
|
+
user_id: dbTargetUser.id,
|
|
128
|
+
};
|
|
129
|
+
await pgClient.query({
|
|
130
|
+
text: `
|
|
131
|
+
SELECT pg_notify('hub:chat:${identity.session.experience_id}', $1::text)
|
|
132
|
+
`,
|
|
133
|
+
values: [JSON.stringify(notifyPayload)],
|
|
134
|
+
});
|
|
135
|
+
return dbActiveMute.id;
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
return object({
|
|
139
|
+
chatMute: chatMuteTable.get({ id: inhibitOnNull($muteId) }),
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GraphQLError } from "graphql";
|
|
2
|
-
import {
|
|
2
|
+
import { extendSchema, gql } from "postgraphile/utils";
|
|
3
3
|
import { assert } from "tsafe";
|
|
4
4
|
import { GET_USER_FROM_USER_TOKEN } from "../graphql-queries.js";
|
|
5
5
|
import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
@@ -22,7 +22,7 @@ const InputSchema = z.object({
|
|
|
22
22
|
casinoBaseUrl: BaseUrlSchema,
|
|
23
23
|
userToken: z.string().min(1, "User token required"),
|
|
24
24
|
});
|
|
25
|
-
export const HubAuthenticatePlugin =
|
|
25
|
+
export const HubAuthenticatePlugin = extendSchema(() => {
|
|
26
26
|
return {
|
|
27
27
|
typeDefs: gql `
|
|
28
28
|
input HubAuthenticateInput {
|
|
@@ -124,34 +124,52 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
124
124
|
assert(mpUserId);
|
|
125
125
|
const uname = result.user.uname;
|
|
126
126
|
assert(uname);
|
|
127
|
-
const
|
|
127
|
+
const mpExperience = result.experience;
|
|
128
|
+
assert(mpExperience);
|
|
129
|
+
assert(mpExperience.userByUserId, "Expected mpExperience.userByUserId");
|
|
130
|
+
const authUser = await pgClient
|
|
128
131
|
.query({
|
|
129
132
|
text: `
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
INSERT INTO hub.user(casino_id, mp_user_id, uname)
|
|
134
|
+
VALUES ($1, $2, $3)
|
|
135
|
+
ON CONFLICT (casino_id, mp_user_id) DO UPDATE
|
|
136
|
+
SET uname = EXCLUDED.uname
|
|
137
|
+
RETURNING id, uname
|
|
138
|
+
`,
|
|
136
139
|
values: [casino.id, mpUserId, uname],
|
|
137
140
|
})
|
|
138
141
|
.then(exactlyOneRow);
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
const ownerUser = await pgClient
|
|
143
|
+
.query({
|
|
144
|
+
text: `
|
|
145
|
+
INSERT INTO hub.user(casino_id, mp_user_id, uname)
|
|
146
|
+
VALUES ($1, $2, $3)
|
|
147
|
+
ON CONFLICT (casino_id, mp_user_id) DO UPDATE
|
|
148
|
+
SET uname = EXCLUDED.uname
|
|
149
|
+
RETURNING id
|
|
150
|
+
`,
|
|
151
|
+
values: [
|
|
152
|
+
casino.id,
|
|
153
|
+
mpExperience.userByUserId.id,
|
|
154
|
+
mpExperience.userByUserId.uname,
|
|
155
|
+
],
|
|
156
|
+
})
|
|
157
|
+
.then(exactlyOneRow);
|
|
158
|
+
const userId = authUser.id;
|
|
142
159
|
const dbExperience = await pgClient
|
|
143
160
|
.query({
|
|
144
161
|
text: `
|
|
145
|
-
INSERT INTO hub.experience(casino_id, mp_experience_id, name)
|
|
146
|
-
VALUES($1, $2, $3)
|
|
162
|
+
INSERT INTO hub.experience(casino_id, mp_experience_id, name, user_id)
|
|
163
|
+
VALUES($1, $2, $3, $4)
|
|
147
164
|
ON CONFLICT (casino_id, mp_experience_id) DO UPDATE
|
|
148
165
|
SET name = EXCLUDED.name
|
|
149
|
-
RETURNING id
|
|
166
|
+
RETURNING id, user_id
|
|
150
167
|
`,
|
|
151
168
|
values: [
|
|
152
169
|
casino.id,
|
|
153
170
|
mpExperience.id,
|
|
154
171
|
mpExperience.name,
|
|
172
|
+
ownerUser.id,
|
|
155
173
|
],
|
|
156
174
|
})
|
|
157
175
|
.then(exactlyOneRow);
|
|
@@ -172,7 +190,7 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
172
190
|
.then(exactlyOneRow);
|
|
173
191
|
const ret = {
|
|
174
192
|
userId,
|
|
175
|
-
uname:
|
|
193
|
+
uname: authUser.uname,
|
|
176
194
|
experienceId: dbExperience.id,
|
|
177
195
|
sessionKey: dbSession.key,
|
|
178
196
|
};
|
|
@@ -185,14 +203,17 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
185
203
|
experience_id: dbExperience.id,
|
|
186
204
|
session_id: dbSession.id,
|
|
187
205
|
is_playground: false,
|
|
206
|
+
is_experience_owner: dbExperience.user_id === userId,
|
|
188
207
|
},
|
|
189
208
|
};
|
|
190
|
-
|
|
209
|
+
const pgSettings = {
|
|
191
210
|
"session.user_id": userId,
|
|
192
211
|
"session.casino_id": casino.id,
|
|
193
212
|
"session.experience_id": dbExperience.id,
|
|
194
213
|
"session.session_id": dbSession.id,
|
|
214
|
+
"session.is_experience_owner": dbExperience.user_id === userId ? "1" : undefined,
|
|
195
215
|
};
|
|
216
|
+
context.pgSettings = pgSettings;
|
|
196
217
|
return ret;
|
|
197
218
|
});
|
|
198
219
|
});
|
|
@@ -4,16 +4,18 @@ import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
|
4
4
|
import { constant, context, object, sideEffect } from "postgraphile/grafast";
|
|
5
5
|
import { withPgPoolTransaction, } from "../db/index.js";
|
|
6
6
|
import { logger } from "../logger.js";
|
|
7
|
-
import { z } from "zod";
|
|
7
|
+
import { z } from "zod/v4";
|
|
8
8
|
import { prettifyError } from "zod/v4";
|
|
9
9
|
const InputSchema = z.object({
|
|
10
|
-
|
|
10
|
+
experienceClientId: z.uuid().optional(),
|
|
11
|
+
userClientId: z.uuid().optional(),
|
|
11
12
|
});
|
|
12
13
|
export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
13
14
|
return {
|
|
14
15
|
typeDefs: gql `
|
|
15
16
|
input HubCreatePlaygroundSessionInput {
|
|
16
|
-
|
|
17
|
+
experienceClientId: UUID
|
|
18
|
+
userClientId: UUID
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
extend type Mutation {
|
|
@@ -31,9 +33,9 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
31
33
|
const $superuserPool = $context.get("superuserPool");
|
|
32
34
|
const $success = sideEffect([$input, $superuserPool, $context], ([rawInput, superuserPool, context]) => {
|
|
33
35
|
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
34
|
-
let
|
|
36
|
+
let input;
|
|
35
37
|
try {
|
|
36
|
-
|
|
38
|
+
input = InputSchema.parse(rawInput);
|
|
37
39
|
}
|
|
38
40
|
catch (e) {
|
|
39
41
|
if (e instanceof z.ZodError) {
|
|
@@ -47,6 +49,7 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
47
49
|
SELECT c.*
|
|
48
50
|
FROM hub.casino c
|
|
49
51
|
WHERE c.is_playground = true
|
|
52
|
+
ORDER BY c.id ASC
|
|
50
53
|
LIMIT 1
|
|
51
54
|
`,
|
|
52
55
|
values: [],
|
|
@@ -60,28 +63,51 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
60
63
|
const dbUser = await pgClient
|
|
61
64
|
.query({
|
|
62
65
|
text: `
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
with ins as (
|
|
67
|
+
insert into hub.user (casino_id, mp_user_id, uname, client_id)
|
|
68
|
+
values ($1, $2, $3, $4)
|
|
69
|
+
on conflict (casino_id, client_id) where client_id is not null
|
|
70
|
+
do nothing
|
|
71
|
+
returning id, uname, mp_user_id
|
|
72
|
+
)
|
|
73
|
+
select id, uname, mp_user_id from ins
|
|
74
|
+
union all
|
|
75
|
+
select id, uname, mp_user_id
|
|
76
|
+
from hub.user
|
|
77
|
+
where casino_id = $1 and client_id = $4
|
|
78
|
+
limit 1
|
|
66
79
|
`,
|
|
67
80
|
values: [
|
|
68
81
|
dbPlaygroundCasino.id,
|
|
69
82
|
DUMMY_MP_ID,
|
|
70
83
|
randomUname,
|
|
84
|
+
input.userClientId ?? null,
|
|
71
85
|
],
|
|
72
86
|
})
|
|
73
87
|
.then(exactlyOneRow);
|
|
74
88
|
const dbExperience = await pgClient
|
|
75
89
|
.query({
|
|
76
90
|
text: `
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
with ins as (
|
|
92
|
+
insert into hub.experience (casino_id, mp_experience_id, name, client_id, user_id)
|
|
93
|
+
values ($1, $2, $3, $4, $5)
|
|
94
|
+
on conflict (casino_id, client_id) where client_id is not null
|
|
95
|
+
do nothing
|
|
96
|
+
returning id, user_id
|
|
97
|
+
)
|
|
98
|
+
select id, user_id from ins
|
|
99
|
+
union all
|
|
100
|
+
select id, user_id
|
|
101
|
+
from hub.experience
|
|
102
|
+
where casino_id = $1 and client_id = $4
|
|
103
|
+
limit 1
|
|
80
104
|
`,
|
|
81
105
|
values: [
|
|
82
106
|
dbPlaygroundCasino.id,
|
|
83
107
|
DUMMY_MP_ID,
|
|
84
108
|
`Playground Experience ${randomUname}`,
|
|
109
|
+
input.experienceClientId ?? null,
|
|
110
|
+
dbUser.id,
|
|
85
111
|
],
|
|
86
112
|
})
|
|
87
113
|
.then(exactlyOneRow);
|
|
@@ -89,6 +115,8 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
89
115
|
text: `
|
|
90
116
|
INSERT INTO hub.balance(user_id, experience_id, casino_id, currency_key, amount)
|
|
91
117
|
VALUES($1, $2, $3, $4, 1000)
|
|
118
|
+
ON CONFLICT (user_id, experience_id, casino_id, currency_key) DO UPDATE
|
|
119
|
+
SET amount = 1000
|
|
92
120
|
`,
|
|
93
121
|
values: [
|
|
94
122
|
dbUser.id,
|
|
@@ -101,7 +129,7 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
101
129
|
.query({
|
|
102
130
|
text: `
|
|
103
131
|
INSERT INTO hub.session(casino_id, user_id, experience_id, user_token, expired_at)
|
|
104
|
-
VALUES($1, $2, $3, $4, now() + interval '1
|
|
132
|
+
VALUES($1, $2, $3, $4, now() + interval '1 week')
|
|
105
133
|
RETURNING id, key
|
|
106
134
|
`,
|
|
107
135
|
values: [
|
|
@@ -127,14 +155,17 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
|
|
|
127
155
|
experience_id: dbExperience.id,
|
|
128
156
|
session_id: dbSession.id,
|
|
129
157
|
is_playground: true,
|
|
158
|
+
is_experience_owner: dbExperience.user_id === dbUser.id,
|
|
130
159
|
},
|
|
131
160
|
};
|
|
132
|
-
|
|
161
|
+
const pgSettings = {
|
|
133
162
|
"session.user_id": dbUser.id,
|
|
134
163
|
"session.casino_id": dbPlaygroundCasino.id,
|
|
135
164
|
"session.experience_id": dbExperience.id,
|
|
136
165
|
"session.session_id": dbSession.id,
|
|
166
|
+
"session.is_experience_owner": dbExperience.user_id === dbUser.id ? "1" : undefined,
|
|
137
167
|
};
|
|
168
|
+
context.pgSettings = pgSettings;
|
|
138
169
|
return ret;
|
|
139
170
|
});
|
|
140
171
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { access, context, object, ObjectStep, sideEffect, } from "postgraphile/grafast";
|
|
2
|
-
import { gql,
|
|
2
|
+
import { gql, extendSchema } from "postgraphile/utils";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { GraphQLError } from "graphql";
|
|
5
|
-
import { DbHashKind,
|
|
5
|
+
import { DbHashKind, dbLockHouseBankroll, dbLockPlayerBalance, exactlyOneRow, maybeOneRow, 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 } from "../hash-chain/get-hash.js";
|
|
@@ -71,7 +71,7 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
|
|
|
71
71
|
export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
72
72
|
BetConfigsSchema.parse(betConfigs);
|
|
73
73
|
const betKinds = Object.keys(betConfigs);
|
|
74
|
-
return
|
|
74
|
+
return extendSchema((build) => {
|
|
75
75
|
const outcomeBetTable = build.input.pgRegistry.pgResources.hub_outcome_bet;
|
|
76
76
|
const typeDefs = gql `
|
|
77
77
|
enum BetKind {
|
|
@@ -171,14 +171,14 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
171
171
|
throw new GraphQLError("Currency not found");
|
|
172
172
|
}
|
|
173
173
|
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
174
|
-
const
|
|
174
|
+
const dbPlayerBalance = await dbLockPlayerBalance(pgClient, {
|
|
175
175
|
userId: session.user_id,
|
|
176
176
|
casinoId: session.casino_id,
|
|
177
177
|
experienceId: session.experience_id,
|
|
178
178
|
currencyKey: dbCurrency.key,
|
|
179
179
|
});
|
|
180
|
-
if (!
|
|
181
|
-
throw new GraphQLError("No balance entry found for player
|
|
180
|
+
if (!dbPlayerBalance) {
|
|
181
|
+
throw new GraphQLError("No balance entry found for player");
|
|
182
182
|
}
|
|
183
183
|
const minProfit = Math.min(...input.outcomes.map((o) => o.profit));
|
|
184
184
|
const maxPlayerLoss = Math.abs(input.wager * minProfit);
|
|
@@ -194,21 +194,6 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
194
194
|
}
|
|
195
195
|
throw new GraphQLError("You cannot afford the worst outcome");
|
|
196
196
|
}
|
|
197
|
-
const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
|
|
198
|
-
const maxPotentialPayout = input.wager * maxProfitMultiplier;
|
|
199
|
-
const riskResult = validateRisk({
|
|
200
|
-
currency: input.currency,
|
|
201
|
-
wager: input.wager,
|
|
202
|
-
bankroll: dbHouseBankroll.amount,
|
|
203
|
-
maxPotentialPayout,
|
|
204
|
-
riskPolicy: betConfig.riskPolicy,
|
|
205
|
-
displayUnitName: dbCurrency.display_unit_name,
|
|
206
|
-
displayUnitScale: dbCurrency.display_unit_scale,
|
|
207
|
-
outcomes: input.outcomes,
|
|
208
|
-
});
|
|
209
|
-
if (!riskResult.ok) {
|
|
210
|
-
throw new GraphQLError(riskResult.error);
|
|
211
|
-
}
|
|
212
197
|
const dbHashChain = await dbLockHubHashChain(pgClient, {
|
|
213
198
|
userId: session.user_id,
|
|
214
199
|
experienceId: session.experience_id,
|
|
@@ -289,26 +274,47 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
289
274
|
const outcome = input.outcomes[outcomeIdx];
|
|
290
275
|
const netPlayerAmount = input.wager * outcome.profit;
|
|
291
276
|
const houseBankrollDelta = -netPlayerAmount;
|
|
292
|
-
await pgClient
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
SET amount = amount + $1
|
|
296
|
-
WHERE id = $2
|
|
297
|
-
`,
|
|
298
|
-
values: [netPlayerAmount, dbPlayerBalance.id],
|
|
277
|
+
const dbHouseBankroll = await dbLockHouseBankroll(pgClient, {
|
|
278
|
+
casinoId: session.casino_id,
|
|
279
|
+
currencyKey: dbCurrency.key,
|
|
299
280
|
});
|
|
281
|
+
if (!dbHouseBankroll) {
|
|
282
|
+
throw new GraphQLError("No house bankroll found");
|
|
283
|
+
}
|
|
284
|
+
const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
|
|
285
|
+
const maxPotentialPayout = input.wager * maxProfitMultiplier;
|
|
286
|
+
const riskResult = validateRisk({
|
|
287
|
+
currency: input.currency,
|
|
288
|
+
wager: input.wager,
|
|
289
|
+
bankroll: dbHouseBankroll.amount,
|
|
290
|
+
maxPotentialPayout,
|
|
291
|
+
riskPolicy: betConfig.riskPolicy,
|
|
292
|
+
displayUnitName: dbCurrency.display_unit_name,
|
|
293
|
+
displayUnitScale: dbCurrency.display_unit_scale,
|
|
294
|
+
outcomes: input.outcomes,
|
|
295
|
+
});
|
|
296
|
+
if (!riskResult.ok) {
|
|
297
|
+
throw new GraphQLError(riskResult.error);
|
|
298
|
+
}
|
|
300
299
|
await pgClient.query({
|
|
301
300
|
text: `
|
|
301
|
+
WITH balance_update AS (
|
|
302
|
+
UPDATE hub.balance
|
|
303
|
+
SET amount = amount + $1
|
|
304
|
+
WHERE id = $2
|
|
305
|
+
)
|
|
302
306
|
UPDATE hub.bankroll
|
|
303
|
-
SET amount = amount + $
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
WHERE id = $
|
|
307
|
+
SET amount = amount + $3,
|
|
308
|
+
wagered = wagered + $4,
|
|
309
|
+
bets = bets + 1
|
|
310
|
+
WHERE id = $5
|
|
307
311
|
`,
|
|
308
312
|
values: [
|
|
309
|
-
|
|
313
|
+
netPlayerAmount,
|
|
314
|
+
dbPlayerBalance.id,
|
|
310
315
|
houseBankrollDelta,
|
|
311
316
|
input.wager,
|
|
317
|
+
dbHouseBankroll.id,
|
|
312
318
|
],
|
|
313
319
|
});
|
|
314
320
|
const immutableData = structuredClone({
|
|
@@ -8,6 +8,7 @@ export type UserSessionContext = {
|
|
|
8
8
|
experience_id: string;
|
|
9
9
|
session_id: string;
|
|
10
10
|
is_playground: boolean;
|
|
11
|
+
is_experience_owner: boolean;
|
|
11
12
|
};
|
|
12
13
|
export type PluginIdentity = {
|
|
13
14
|
kind: "user";
|
|
@@ -15,12 +16,23 @@ export type PluginIdentity = {
|
|
|
15
16
|
} | {
|
|
16
17
|
kind: "operator";
|
|
17
18
|
};
|
|
19
|
+
export type OurPgSettings = {
|
|
20
|
+
"session.user_id": string;
|
|
21
|
+
"session.experience_id": string;
|
|
22
|
+
"session.casino_id": string;
|
|
23
|
+
"session.session_id": string;
|
|
24
|
+
"session.is_experience_owner": "1" | undefined;
|
|
25
|
+
} | {
|
|
26
|
+
"operator.api_key": string;
|
|
27
|
+
};
|
|
18
28
|
export declare const requiredPlugins: readonly GraphileConfig.Plugin[];
|
|
19
29
|
export declare const defaultPlugins: readonly GraphileConfig.Plugin[];
|
|
20
|
-
export declare function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }: {
|
|
30
|
+
export declare function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: {
|
|
21
31
|
plugins: readonly GraphileConfig.Plugin[];
|
|
22
32
|
exportSchemaSDLPath?: string;
|
|
23
33
|
extraPgSchemas: string[];
|
|
24
34
|
abortSignal: AbortSignal;
|
|
25
35
|
context: ServerContext;
|
|
36
|
+
enableChat: boolean;
|
|
37
|
+
enablePlayground: boolean;
|
|
26
38
|
}): GraphileConfig.Preset;
|
|
@@ -25,6 +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 { HubChatCreateUserMessagePlugin } from "../plugins/chat/hub-chat-create-user-message.js";
|
|
29
|
+
import { HubChatSubscriptionPlugin } from "../plugins/chat/hub-chat-subscription.js";
|
|
30
|
+
import { HubCreatePlaygroundSessionPlugin } from "../plugins/hub-create-playground-session.js";
|
|
31
|
+
import { HubChatUnmuteUserPlugin } from "../plugins/chat/hub-chat-unmute-user.js";
|
|
32
|
+
import { HubChatMuteUserPlugin } from "../plugins/chat/hub-chat-mute-user.js";
|
|
33
|
+
import { HubChatCreateSystemMessagePlugin } from "../plugins/chat/hub-chat-create-system-message.js";
|
|
34
|
+
import { HubChatAfterIdConditionPlugin } from "../plugins/chat/hub-chat-after-id-condition.js";
|
|
28
35
|
export const requiredPlugins = [
|
|
29
36
|
SmartTagsPlugin,
|
|
30
37
|
IdToNodeIdPlugin,
|
|
@@ -48,7 +55,7 @@ export const defaultPlugins = [
|
|
|
48
55
|
HubPreimageHashFieldPlugin,
|
|
49
56
|
customPgOmitArchivedPlugin("deleted"),
|
|
50
57
|
];
|
|
51
|
-
export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }) {
|
|
58
|
+
export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }) {
|
|
52
59
|
if (exportSchemaSDLPath) {
|
|
53
60
|
if (!exportSchemaSDLPath.startsWith("/")) {
|
|
54
61
|
throw new Error("exportSchemaSDLPath must be an absolute path");
|
|
@@ -65,6 +72,12 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
65
72
|
mutablePlugins.unshift(requiredPlugin);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
75
|
+
if (enablePlayground) {
|
|
76
|
+
mutablePlugins.push(HubCreatePlaygroundSessionPlugin);
|
|
77
|
+
}
|
|
78
|
+
if (enableChat) {
|
|
79
|
+
mutablePlugins.push(HubChatCreateUserMessagePlugin, HubChatCreateSystemMessagePlugin, HubChatSubscriptionPlugin, HubChatMuteUserPlugin, HubChatUnmuteUserPlugin, HubChatAfterIdConditionPlugin);
|
|
80
|
+
}
|
|
68
81
|
const preset = {
|
|
69
82
|
extends: [PostGraphileAmberPreset],
|
|
70
83
|
disablePlugins: ["NodePlugin"],
|
|
@@ -116,19 +129,29 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
116
129
|
experience_id: reqIdentity.user.experience_id,
|
|
117
130
|
session_id: reqIdentity.sessionId,
|
|
118
131
|
is_playground: reqIdentity.isPlayground,
|
|
132
|
+
is_experience_owner: reqIdentity.isExperienceOwner,
|
|
119
133
|
},
|
|
120
134
|
};
|
|
121
135
|
}
|
|
122
136
|
const pgSettings = {};
|
|
137
|
+
let ourPgSettings;
|
|
123
138
|
if (reqIdentity?.kind === "user") {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
ourPgSettings = {
|
|
140
|
+
"session.user_id": reqIdentity.user.id,
|
|
141
|
+
"session.experience_id": reqIdentity.user.experience_id,
|
|
142
|
+
"session.casino_id": reqIdentity.user.casino_id,
|
|
143
|
+
"session.session_id": reqIdentity.sessionId,
|
|
144
|
+
"session.is_experience_owner": reqIdentity.isExperienceOwner
|
|
145
|
+
? "1"
|
|
146
|
+
: undefined,
|
|
147
|
+
};
|
|
128
148
|
}
|
|
129
149
|
else if (reqIdentity?.kind === "operator") {
|
|
130
|
-
|
|
150
|
+
ourPgSettings = {
|
|
151
|
+
"operator.api_key": reqIdentity.apiKey,
|
|
152
|
+
};
|
|
131
153
|
}
|
|
154
|
+
Object.assign(pgSettings, ourPgSettings);
|
|
132
155
|
return {
|
|
133
156
|
pgSettings,
|
|
134
157
|
identity: pluginIdentity,
|
|
@@ -165,14 +188,17 @@ async function handleWebsocketContext(context, ws) {
|
|
|
165
188
|
experience_id: result.user.experience_id,
|
|
166
189
|
session_id: result.sessionId,
|
|
167
190
|
is_playground: result.isPlayground,
|
|
191
|
+
is_experience_owner: result.isExperienceOwner,
|
|
192
|
+
};
|
|
193
|
+
const pgSettings = {
|
|
194
|
+
"session.user_id": result.user.id,
|
|
195
|
+
"session.experience_id": result.user.experience_id,
|
|
196
|
+
"session.casino_id": result.user.casino_id,
|
|
197
|
+
"session.session_id": result.sessionId,
|
|
198
|
+
"session.is_experience_owner": result.isExperienceOwner ? "1" : undefined,
|
|
168
199
|
};
|
|
169
200
|
return {
|
|
170
|
-
pgSettings
|
|
171
|
-
"session.user_id": result.user.id,
|
|
172
|
-
"session.experience_id": result.user.experience_id,
|
|
173
|
-
"session.casino_id": result.user.casino_id,
|
|
174
|
-
"session.session_id": result.sessionId,
|
|
175
|
-
},
|
|
201
|
+
pgSettings,
|
|
176
202
|
identity: {
|
|
177
203
|
kind: "user",
|
|
178
204
|
session,
|
|
@@ -4,7 +4,9 @@ export type HubServer = {
|
|
|
4
4
|
listen: () => Promise<void>;
|
|
5
5
|
shutdown: () => Promise<void>;
|
|
6
6
|
};
|
|
7
|
-
export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
|
|
7
|
+
export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
|
|
8
8
|
abortSignal: AbortSignal;
|
|
9
9
|
context: ServerContext;
|
|
10
|
+
enableChat: boolean;
|
|
11
|
+
enablePlayground: boolean;
|
|
10
12
|
}): HubServer;
|