@moneypot/hub 0.0.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/README.md +108 -0
- package/dist/cli/add-casino.d.ts +2 -0
- package/dist/cli/add-casino.js +116 -0
- package/dist/dashboard/assets/index-BtrbrisP.js +360 -0
- package/dist/dashboard/assets/index-tK7EUtyc.css +5 -0
- package/dist/dashboard/index.html +13 -0
- package/dist/src/GraphQLError.d.ts +8 -0
- package/dist/src/GraphQLError.js +79 -0
- package/dist/src/__generated__/fragment-masking.d.ts +19 -0
- package/dist/src/__generated__/fragment-masking.js +16 -0
- package/dist/src/__generated__/gql.d.ts +26 -0
- package/dist/src/__generated__/gql.js +15 -0
- package/dist/src/__generated__/graphql.d.ts +3129 -0
- package/dist/src/__generated__/graphql.js +454 -0
- package/dist/src/__generated__/index.d.ts +2 -0
- package/dist/src/__generated__/index.js +2 -0
- package/dist/src/config.d.ts +14 -0
- package/dist/src/config.js +57 -0
- package/dist/src/db/index.d.ts +89 -0
- package/dist/src/db/index.js +339 -0
- package/dist/src/db/internal.d.ts +7 -0
- package/dist/src/db/internal.js +33 -0
- package/dist/src/db/public.d.ts +7 -0
- package/dist/src/db/public.js +20 -0
- package/dist/src/db/types.d.ts +80 -0
- package/dist/src/db/types.js +1 -0
- package/dist/src/db/util.d.ts +6 -0
- package/dist/src/db/util.js +9 -0
- package/dist/src/express.d.ts +13 -0
- package/dist/src/express.js +1 -0
- package/dist/src/grafast.d.ts +1 -0
- package/dist/src/grafast.js +1 -0
- package/dist/src/graphile.d.ts +1 -0
- package/dist/src/graphile.js +1 -0
- package/dist/src/graphql-client.d.ts +6 -0
- package/dist/src/graphql-client.js +8 -0
- package/dist/src/graphql-queries.d.ts +18 -0
- package/dist/src/graphql-queries.js +123 -0
- package/dist/src/graphql.d.ts +1 -0
- package/dist/src/graphql.js +1 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.js +65 -0
- package/dist/src/logger.d.ts +9 -0
- package/dist/src/logger.js +21 -0
- package/dist/src/pg-versions/001-schema.sql +456 -0
- package/dist/src/plugins/caas-add-casino.d.ts +1 -0
- package/dist/src/plugins/caas-add-casino.js +150 -0
- package/dist/src/plugins/caas-authenticate.d.ts +1 -0
- package/dist/src/plugins/caas-authenticate.js +175 -0
- package/dist/src/plugins/caas-balance-alert.d.ts +1 -0
- package/dist/src/plugins/caas-balance-alert.js +43 -0
- package/dist/src/plugins/caas-claim-faucet.d.ts +1 -0
- package/dist/src/plugins/caas-claim-faucet.js +85 -0
- package/dist/src/plugins/caas-current-x.d.ts +1 -0
- package/dist/src/plugins/caas-current-x.js +62 -0
- package/dist/src/plugins/caas-schema-prefix.d.ts +1 -0
- package/dist/src/plugins/caas-schema-prefix.js +25 -0
- package/dist/src/plugins/caas-user-balance-by-currency.d.ts +1 -0
- package/dist/src/plugins/caas-user-balance-by-currency.js +55 -0
- package/dist/src/plugins/caas-withdraw.d.ts +1 -0
- package/dist/src/plugins/caas-withdraw.js +133 -0
- package/dist/src/plugins/debug.d.ts +1 -0
- package/dist/src/plugins/debug.js +14 -0
- package/dist/src/plugins/hub-add-casino.d.ts +1 -0
- package/dist/src/plugins/hub-add-casino.js +150 -0
- package/dist/src/plugins/hub-authenticate.d.ts +1 -0
- package/dist/src/plugins/hub-authenticate.js +175 -0
- package/dist/src/plugins/hub-balance-alert.d.ts +1 -0
- package/dist/src/plugins/hub-balance-alert.js +43 -0
- package/dist/src/plugins/hub-claim-faucet.d.ts +1 -0
- package/dist/src/plugins/hub-claim-faucet.js +85 -0
- package/dist/src/plugins/hub-current-x.d.ts +1 -0
- package/dist/src/plugins/hub-current-x.js +62 -0
- package/dist/src/plugins/hub-schema-prefix.d.ts +1 -0
- package/dist/src/plugins/hub-schema-prefix.js +25 -0
- package/dist/src/plugins/hub-user-balance-by-currency.d.ts +1 -0
- package/dist/src/plugins/hub-user-balance-by-currency.js +55 -0
- package/dist/src/plugins/hub-withdraw.d.ts +1 -0
- package/dist/src/plugins/hub-withdraw.js +133 -0
- package/dist/src/plugins/id-to-node-id.d.ts +1 -0
- package/dist/src/plugins/id-to-node-id.js +31 -0
- package/dist/src/plugins/validate-fields.d.ts +1 -0
- package/dist/src/plugins/validate-fields.js +61 -0
- package/dist/src/process-transfers.d.ts +7 -0
- package/dist/src/process-transfers.js +413 -0
- package/dist/src/process-withdrawal-request.d.ts +5 -0
- package/dist/src/process-withdrawal-request.js +129 -0
- package/dist/src/server/graphile.config.d.ts +33 -0
- package/dist/src/server/graphile.config.js +166 -0
- package/dist/src/server/handle-errors.d.ts +10 -0
- package/dist/src/server/handle-errors.js +88 -0
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.js +69 -0
- package/dist/src/server/middleware/authentication.d.ts +4 -0
- package/dist/src/server/middleware/authentication.js +55 -0
- package/dist/src/server/middleware/cors.d.ts +3 -0
- package/dist/src/server/middleware/cors.js +14 -0
- package/dist/src/services/jwt-service.d.ts +13 -0
- package/dist/src/services/jwt-service.js +131 -0
- package/dist/src/smart-tags.d.ts +1 -0
- package/dist/src/smart-tags.js +55 -0
- package/dist/src/util.d.ts +12 -0
- package/dist/src/util.js +4 -0
- package/dist/src/validate.d.ts +9 -0
- package/dist/src/validate.js +91 -0
- package/package.json +69 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { constant, context, object, sideEffect } from "postgraphile/grafast";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { superuserPool, withPgPoolTransaction, } from "../db/index.js";
|
|
4
|
+
import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
5
|
+
import { GraphQLError } from "graphql";
|
|
6
|
+
export const CaasWithdrawPlugin = makeExtendSchemaPlugin((build) => {
|
|
7
|
+
const caasWithdrawalRequests = build.input.pgRegistry.pgResources.caas_withdrawal_request;
|
|
8
|
+
return {
|
|
9
|
+
typeDefs: gql `
|
|
10
|
+
input CaasWithdrawInput {
|
|
11
|
+
amount: Int!
|
|
12
|
+
currency: String!
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type CaasWithdrawPayload {
|
|
16
|
+
withdrawalRequest: CaasWithdrawalRequest!
|
|
17
|
+
query: Query
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
extend type Mutation {
|
|
21
|
+
caasWithdraw(input: CaasWithdrawInput!): CaasWithdrawPayload
|
|
22
|
+
}
|
|
23
|
+
`,
|
|
24
|
+
plans: {
|
|
25
|
+
Mutation: {
|
|
26
|
+
caasWithdraw(_, { $input }) {
|
|
27
|
+
const $identity = context().get("identity");
|
|
28
|
+
const $withdrawalRequestId = sideEffect([$input, $identity], ([input, identity]) => {
|
|
29
|
+
if (identity?.kind !== "user") {
|
|
30
|
+
throw new GraphQLError("You must be logged in");
|
|
31
|
+
}
|
|
32
|
+
const { session } = identity;
|
|
33
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
34
|
+
const { amount, currency } = input;
|
|
35
|
+
if (amount <= 0) {
|
|
36
|
+
throw new GraphQLError("Withdraw amount must be greater than zero");
|
|
37
|
+
}
|
|
38
|
+
if (!Number.isInteger(amount)) {
|
|
39
|
+
throw new GraphQLError("Withdraw amount must be an integer");
|
|
40
|
+
}
|
|
41
|
+
const dbCurrency = await pgClient
|
|
42
|
+
.query({
|
|
43
|
+
text: `
|
|
44
|
+
SELECT key
|
|
45
|
+
FROM caas.currency
|
|
46
|
+
WHERE key = $1 AND casino_id = $2
|
|
47
|
+
`,
|
|
48
|
+
values: [currency, session.casino_id],
|
|
49
|
+
})
|
|
50
|
+
.then(maybeOneRow);
|
|
51
|
+
if (!dbCurrency) {
|
|
52
|
+
throw new GraphQLError("Currency not supported");
|
|
53
|
+
}
|
|
54
|
+
const balance = await pgClient
|
|
55
|
+
.query({
|
|
56
|
+
text: `
|
|
57
|
+
select *
|
|
58
|
+
from caas.balance
|
|
59
|
+
where currency_key = $1
|
|
60
|
+
and user_id = $2
|
|
61
|
+
and casino_id = $3
|
|
62
|
+
and experience_id = $4
|
|
63
|
+
|
|
64
|
+
FOR UPDATE
|
|
65
|
+
`,
|
|
66
|
+
values: [
|
|
67
|
+
currency,
|
|
68
|
+
session.user_id,
|
|
69
|
+
session.casino_id,
|
|
70
|
+
session.experience_id,
|
|
71
|
+
],
|
|
72
|
+
})
|
|
73
|
+
.then(maybeOneRow);
|
|
74
|
+
if (!balance || balance.amount < amount) {
|
|
75
|
+
throw new GraphQLError("Insufficient funds for withdrawal");
|
|
76
|
+
}
|
|
77
|
+
const dbWithdrawalRequest = await pgClient
|
|
78
|
+
.query({
|
|
79
|
+
text: `
|
|
80
|
+
insert into caas.withdrawal_request(
|
|
81
|
+
user_id,
|
|
82
|
+
experience_id,
|
|
83
|
+
casino_id,
|
|
84
|
+
amount,
|
|
85
|
+
currency_key
|
|
86
|
+
)
|
|
87
|
+
values ($1, $2, $3, $4, $5)
|
|
88
|
+
returning id
|
|
89
|
+
`,
|
|
90
|
+
values: [
|
|
91
|
+
session.user_id,
|
|
92
|
+
session.experience_id,
|
|
93
|
+
session.casino_id,
|
|
94
|
+
amount,
|
|
95
|
+
currency,
|
|
96
|
+
],
|
|
97
|
+
})
|
|
98
|
+
.then(exactlyOneRow);
|
|
99
|
+
await pgClient.query({
|
|
100
|
+
text: `
|
|
101
|
+
update caas.balance
|
|
102
|
+
set amount = amount - $1
|
|
103
|
+
where user_id = $2
|
|
104
|
+
and experience_id = $3
|
|
105
|
+
and currency_key = $4
|
|
106
|
+
and casino_id = $5
|
|
107
|
+
`,
|
|
108
|
+
values: [
|
|
109
|
+
amount,
|
|
110
|
+
session.user_id,
|
|
111
|
+
session.experience_id,
|
|
112
|
+
currency,
|
|
113
|
+
session.casino_id,
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
return dbWithdrawalRequest.id;
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
return object({
|
|
120
|
+
withdrawalRequestId: $withdrawalRequestId,
|
|
121
|
+
query: constant(true),
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
CaasWithdrawPayload: {
|
|
126
|
+
withdrawalRequest($data) {
|
|
127
|
+
const $id = $data.get("withdrawalRequestId");
|
|
128
|
+
return caasWithdrawalRequests.get({ id: $id });
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DebugPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { logger } from "../logger.js";
|
|
2
|
+
export const DebugPlugin = {
|
|
3
|
+
name: "DebugPlugin",
|
|
4
|
+
description: "A place to artificially slow down the server to test client",
|
|
5
|
+
version: "0.0.1",
|
|
6
|
+
grafserv: {
|
|
7
|
+
hooks: {
|
|
8
|
+
processGraphQLRequestBody(info, event) {
|
|
9
|
+
const { body } = event;
|
|
10
|
+
logger.debug("GraphQL request:", body.operationName, body.variableValues);
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubAddCasinoPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { constant, context, object, sideEffect } from "postgraphile/grafast";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { exactlyOneRow } from "../db/util.js";
|
|
4
|
+
import { gql as generatedGql } from "../__generated__/gql.js";
|
|
5
|
+
import { GraphQLClient } from "graphql-request";
|
|
6
|
+
import { GraphQLError } from "graphql";
|
|
7
|
+
import { superuserPool, upsertCurrencies, withPgPoolTransaction, } from "../db/index.js";
|
|
8
|
+
import { logger } from "../logger.js";
|
|
9
|
+
import { assert, is } from "tsafe";
|
|
10
|
+
import * as jwtService from "../services/jwt-service.js";
|
|
11
|
+
import { startTransferProcessor } from "../process-transfers.js";
|
|
12
|
+
const GET_CURRENT_CONTROLLER = generatedGql(`
|
|
13
|
+
query GetCurrentController {
|
|
14
|
+
currentController {
|
|
15
|
+
id
|
|
16
|
+
}
|
|
17
|
+
allCurrencies {
|
|
18
|
+
nodes {
|
|
19
|
+
id
|
|
20
|
+
displayUnitName
|
|
21
|
+
displayUnitScale
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`);
|
|
26
|
+
export const HubAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
|
|
27
|
+
const casinoTable = build.input.pgRegistry.pgResources.hub_casino;
|
|
28
|
+
return {
|
|
29
|
+
typeDefs: gql `
|
|
30
|
+
input HubAddCasinoInput {
|
|
31
|
+
name: String!
|
|
32
|
+
baseUrl: String!
|
|
33
|
+
graphqlUrl: String!
|
|
34
|
+
apiKey: String!
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type HubAddCasinoPayload {
|
|
38
|
+
casino: HubCasino
|
|
39
|
+
query: Query
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
extend type Mutation {
|
|
43
|
+
hubAddCasino(input: HubAddCasinoInput!): HubAddCasinoPayload
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
plans: {
|
|
47
|
+
Mutation: {
|
|
48
|
+
hubAddCasino(_, { $input }) {
|
|
49
|
+
const $identity = context().get("identity");
|
|
50
|
+
const $casinoId = sideEffect([$input, $identity], ([input, identity]) => {
|
|
51
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
52
|
+
if (identity?.kind !== "operator") {
|
|
53
|
+
throw new GraphQLError("Unauthorized");
|
|
54
|
+
}
|
|
55
|
+
assert(is(input));
|
|
56
|
+
const { name, baseUrl, graphqlUrl, apiKey } = input;
|
|
57
|
+
const graphqlClient = new GraphQLClient(graphqlUrl, {
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `apikey:${apiKey}`,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
console.log(`[hubAddCasino] Making request to ${graphqlUrl}`);
|
|
63
|
+
const result = await graphqlClient
|
|
64
|
+
.request(GET_CURRENT_CONTROLLER)
|
|
65
|
+
.catch((e) => {
|
|
66
|
+
if (e.cause?.code === "ECONNREFUSED" ||
|
|
67
|
+
e.cause?.code === "ENOTFOUND") {
|
|
68
|
+
throw new GraphQLError(`Cannot connect to graphqlUrl`);
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
71
|
+
});
|
|
72
|
+
if (!result) {
|
|
73
|
+
throw new GraphQLError("Invalid API key");
|
|
74
|
+
}
|
|
75
|
+
if (!result.currentController) {
|
|
76
|
+
throw new GraphQLError("Invalid API key");
|
|
77
|
+
}
|
|
78
|
+
let casino;
|
|
79
|
+
try {
|
|
80
|
+
casino = await pgClient
|
|
81
|
+
.query({
|
|
82
|
+
text: `
|
|
83
|
+
INSERT INTO hub.casino(name, base_url, graphql_url)
|
|
84
|
+
VALUES($1, $2, $3)
|
|
85
|
+
returning id
|
|
86
|
+
`,
|
|
87
|
+
values: [name, baseUrl, graphqlUrl],
|
|
88
|
+
})
|
|
89
|
+
.then((res) => {
|
|
90
|
+
console.log("res", res.rows);
|
|
91
|
+
return res;
|
|
92
|
+
})
|
|
93
|
+
.then(exactlyOneRow);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (e instanceof Error &&
|
|
97
|
+
"code" in e &&
|
|
98
|
+
e.code === "23505" &&
|
|
99
|
+
"constraint" in e) {
|
|
100
|
+
switch (e.constraint) {
|
|
101
|
+
case "casino_graphql_url_idx":
|
|
102
|
+
throw new GraphQLError("Casino with that graphqlUrl already exists");
|
|
103
|
+
case "casino_base_url_idx":
|
|
104
|
+
throw new GraphQLError("Casino with that baseUrl already exists");
|
|
105
|
+
default:
|
|
106
|
+
throw new GraphQLError(`Duplicate constraint violation: ${e.constraint}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
logger.error("Error adding casino", e);
|
|
110
|
+
throw e;
|
|
111
|
+
}
|
|
112
|
+
await pgClient.query({
|
|
113
|
+
text: `
|
|
114
|
+
INSERT INTO hub.casino_secret(id, controller_id, api_key)
|
|
115
|
+
VALUES($1, $2, $3)
|
|
116
|
+
`,
|
|
117
|
+
values: [casino.id, result.currentController.id, apiKey],
|
|
118
|
+
});
|
|
119
|
+
const currencies = result.allCurrencies?.nodes.flatMap((x) => x || []) || [];
|
|
120
|
+
await upsertCurrencies(pgClient, {
|
|
121
|
+
casinoId: casino.id,
|
|
122
|
+
currencies,
|
|
123
|
+
});
|
|
124
|
+
await pgClient.query({
|
|
125
|
+
text: `
|
|
126
|
+
INSERT INTO hub.bankroll (casino_id, currency_key)
|
|
127
|
+
SELECT casino_id, key
|
|
128
|
+
FROM hub.currency
|
|
129
|
+
WHERE casino_id = $1
|
|
130
|
+
`,
|
|
131
|
+
values: [casino.id],
|
|
132
|
+
});
|
|
133
|
+
logger.info(`Fetching JWKS for new casino from ${graphqlUrl}...`);
|
|
134
|
+
await jwtService.refreshCasinoJwksTask(pgClient, {
|
|
135
|
+
graphqlClient,
|
|
136
|
+
casinoId: casino.id,
|
|
137
|
+
});
|
|
138
|
+
startTransferProcessor({ casinoId: casino.id });
|
|
139
|
+
return casino.id;
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
return object({
|
|
143
|
+
casino: casinoTable.get({ id: $casinoId }),
|
|
144
|
+
query: constant(true),
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubAuthenticatePlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { assert, is } from "tsafe";
|
|
4
|
+
import { GET_USER_FROM_USER_TOKEN } from "../graphql-queries.js";
|
|
5
|
+
import { exactlyOneRow, maybeOneRow } from "../db/util.js";
|
|
6
|
+
import { createGraphqlClient } from "../graphql-client.js";
|
|
7
|
+
import { constant, context, error, object, sideEffect, } from "postgraphile/grafast";
|
|
8
|
+
import { superuserPool, withPgPoolTransaction, } from "../db/index.js";
|
|
9
|
+
import { logger } from "../logger.js";
|
|
10
|
+
import * as jwtService from "../services/jwt-service.js";
|
|
11
|
+
import { extractGraphQLErrorInfo, isGraphQLError } from "../GraphQLError.js";
|
|
12
|
+
export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
13
|
+
return {
|
|
14
|
+
typeDefs: gql `
|
|
15
|
+
input HubAuthenticateInput {
|
|
16
|
+
casinoBaseUrl: String!
|
|
17
|
+
userToken: String!
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type HubAuthenticateSuccess {
|
|
21
|
+
experienceId: UUID!
|
|
22
|
+
sessionKey: UUID!
|
|
23
|
+
userId: UUID!
|
|
24
|
+
uname: String!
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type HubAuthenticatePayload {
|
|
28
|
+
query: Query
|
|
29
|
+
success: HubAuthenticateSuccess
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
extend type Mutation {
|
|
33
|
+
hubAuthenticate(input: HubAuthenticateInput!): HubAuthenticatePayload
|
|
34
|
+
}
|
|
35
|
+
`,
|
|
36
|
+
plans: {
|
|
37
|
+
Mutation: {
|
|
38
|
+
hubAuthenticate(_, { $input }) {
|
|
39
|
+
try {
|
|
40
|
+
const $context = context();
|
|
41
|
+
const $success = sideEffect([$input, $context], ([input, context]) => {
|
|
42
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
43
|
+
assert(is(input));
|
|
44
|
+
const { userToken: jwt, casinoBaseUrl } = input;
|
|
45
|
+
const casino = await pgClient
|
|
46
|
+
.query({
|
|
47
|
+
text: `
|
|
48
|
+
SELECT c.*, s.api_key
|
|
49
|
+
FROM hub.casino c
|
|
50
|
+
LEFT JOIN hub.casino_secret s ON c.id = s.id
|
|
51
|
+
WHERE c.base_url = $1`,
|
|
52
|
+
values: [casinoBaseUrl],
|
|
53
|
+
})
|
|
54
|
+
.then(maybeOneRow);
|
|
55
|
+
if (!casino) {
|
|
56
|
+
throw new GraphQLError(`CAAS is unaware of casino with a base url of provided casinoBaseUrl`);
|
|
57
|
+
}
|
|
58
|
+
if (!casino.api_key) {
|
|
59
|
+
throw new GraphQLError("Casino secret not configured");
|
|
60
|
+
}
|
|
61
|
+
const graphqlClient = createGraphqlClient({
|
|
62
|
+
graphqlUrl: casino.graphql_url,
|
|
63
|
+
apiKey: casino.api_key,
|
|
64
|
+
});
|
|
65
|
+
const verifyResult = await jwtService.verifyJwtFromDbCacheAndEnsureNotAlreadyUsed(pgClient, {
|
|
66
|
+
casinoId: casino.id,
|
|
67
|
+
jwt,
|
|
68
|
+
});
|
|
69
|
+
if (!verifyResult.ok) {
|
|
70
|
+
throw new GraphQLError(`Error verifying userToken: ${verifyResult.error}`);
|
|
71
|
+
}
|
|
72
|
+
const { userToken } = verifyResult.value;
|
|
73
|
+
let res;
|
|
74
|
+
try {
|
|
75
|
+
res = await graphqlClient.request(GET_USER_FROM_USER_TOKEN, {
|
|
76
|
+
token: userToken,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
logger.error(`[hubAuthenticate] Error when making GET_USER_FROM_USER_TOKEN to casino:`, e);
|
|
81
|
+
if (isGraphQLError(e)) {
|
|
82
|
+
const errorInfo = extractGraphQLErrorInfo(e);
|
|
83
|
+
if (errorInfo.code === "UNAUTHENTICATED") {
|
|
84
|
+
throw new GraphQLError("Invalid api key");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
throw new GraphQLError(errorInfo.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
const result = res.userFromUserToken;
|
|
93
|
+
if (!result || !result.user || !result.experience) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const mpUserId = result.user.id;
|
|
97
|
+
assert(mpUserId);
|
|
98
|
+
const uname = result.user.uname;
|
|
99
|
+
assert(uname);
|
|
100
|
+
const dbUser = await pgClient
|
|
101
|
+
.query({
|
|
102
|
+
text: `
|
|
103
|
+
INSERT INTO hub.user(casino_id, mp_user_id, uname)
|
|
104
|
+
VALUES($1, $2, $3)
|
|
105
|
+
ON CONFLICT (casino_id, mp_user_id) DO UPDATE
|
|
106
|
+
SET uname = EXCLUDED.uname
|
|
107
|
+
RETURNING id, uname
|
|
108
|
+
`,
|
|
109
|
+
values: [casino.id, mpUserId, uname],
|
|
110
|
+
})
|
|
111
|
+
.then(exactlyOneRow);
|
|
112
|
+
const userId = dbUser.id;
|
|
113
|
+
const mpExperience = result.experience;
|
|
114
|
+
assert(mpExperience);
|
|
115
|
+
const dbExperience = await pgClient
|
|
116
|
+
.query({
|
|
117
|
+
text: `
|
|
118
|
+
INSERT INTO hub.experience(casino_id, mp_experience_id, name)
|
|
119
|
+
VALUES($1, $2, $3)
|
|
120
|
+
ON CONFLICT (casino_id, mp_experience_id) DO UPDATE
|
|
121
|
+
SET name = EXCLUDED.name
|
|
122
|
+
RETURNING id
|
|
123
|
+
`,
|
|
124
|
+
values: [casino.id, mpExperience.id, mpExperience.name],
|
|
125
|
+
})
|
|
126
|
+
.then(exactlyOneRow);
|
|
127
|
+
const dbSession = await pgClient
|
|
128
|
+
.query({
|
|
129
|
+
text: `
|
|
130
|
+
INSERT INTO hub.session(casino_id, user_id, experience_id, user_token)
|
|
131
|
+
VALUES($1, $2, $3, $4)
|
|
132
|
+
RETURNING id, key
|
|
133
|
+
`,
|
|
134
|
+
values: [casino.id, userId, dbExperience.id, userToken],
|
|
135
|
+
})
|
|
136
|
+
.then(exactlyOneRow);
|
|
137
|
+
const ret = {
|
|
138
|
+
userId,
|
|
139
|
+
uname: dbUser.uname,
|
|
140
|
+
experienceId: dbExperience.id,
|
|
141
|
+
sessionKey: dbSession.key,
|
|
142
|
+
};
|
|
143
|
+
context.identity = {
|
|
144
|
+
kind: "user",
|
|
145
|
+
session: {
|
|
146
|
+
user_id: userId,
|
|
147
|
+
mp_user_id: mpUserId,
|
|
148
|
+
casino_id: casino.id,
|
|
149
|
+
experience_id: dbExperience.id,
|
|
150
|
+
session_id: dbSession.id,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
context.pgSettings = {
|
|
154
|
+
"session.user_id": userId,
|
|
155
|
+
"session.casino_id": casino.id,
|
|
156
|
+
"session.experience_id": dbExperience.id,
|
|
157
|
+
"session.session_id": dbSession.id,
|
|
158
|
+
};
|
|
159
|
+
return ret;
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
return object({
|
|
163
|
+
query: constant(true),
|
|
164
|
+
success: $success,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
logger.error(error);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubBalanceAlertPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { makeExtendSchemaPlugin, gql } from "postgraphile/utils";
|
|
2
|
+
import { context, lambda, listen } from "postgraphile/grafast";
|
|
3
|
+
import { jsonParse } from "postgraphile/@dataplan/json";
|
|
4
|
+
export const HubBalanceAlertPlugin = makeExtendSchemaPlugin(() => {
|
|
5
|
+
return {
|
|
6
|
+
typeDefs: gql `
|
|
7
|
+
extend type Subscription {
|
|
8
|
+
hubBalanceAlert: HubBalanceAlertPayload
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type HubBalanceAlertPayload {
|
|
12
|
+
currencyKey: String
|
|
13
|
+
}
|
|
14
|
+
`,
|
|
15
|
+
plans: {
|
|
16
|
+
Subscription: {
|
|
17
|
+
hubBalanceAlert: {
|
|
18
|
+
subscribePlan(_$root) {
|
|
19
|
+
const $pgSubscriber = context().get("pgSubscriber");
|
|
20
|
+
const $identity = context().get("identity");
|
|
21
|
+
const $channelKey = lambda($identity, (identity) => {
|
|
22
|
+
if (identity?.kind === "user") {
|
|
23
|
+
return `hub:user:${identity.session.user_id}:balance_alert`;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return listen($pgSubscriber, $channelKey, jsonParse);
|
|
30
|
+
},
|
|
31
|
+
plan($event) {
|
|
32
|
+
return $event;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
HubBalanceAlertPayload: {
|
|
37
|
+
currencyKey($event) {
|
|
38
|
+
return $event.get("currency_key");
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubClaimFaucetPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { object } from "grafast";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { superuserPool, withPgPoolTransaction } from "../db/index.js";
|
|
4
|
+
import { constant, context, sideEffect } from "postgraphile/grafast";
|
|
5
|
+
const CLAIM_AMOUNT = 1000;
|
|
6
|
+
export const HubClaimFaucetPlugin = makeExtendSchemaPlugin(() => {
|
|
7
|
+
return {
|
|
8
|
+
typeDefs: gql `
|
|
9
|
+
type HubClaimFaucetPayload {
|
|
10
|
+
success: Boolean!
|
|
11
|
+
query: Query
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
extend type Mutation {
|
|
15
|
+
hubClaimFaucet: HubClaimFaucetPayload
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
plans: {
|
|
19
|
+
Mutation: {
|
|
20
|
+
hubClaimFaucet() {
|
|
21
|
+
const $identity = context().get("identity");
|
|
22
|
+
const $result = sideEffect([$identity], ([identity]) => {
|
|
23
|
+
if (identity?.kind !== "user") {
|
|
24
|
+
throw new Error("Must be logged in as user");
|
|
25
|
+
}
|
|
26
|
+
const { session } = identity;
|
|
27
|
+
return withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
28
|
+
await upsertPlayCurrency(pgClient, session.casino_id);
|
|
29
|
+
await pgClient.query({
|
|
30
|
+
text: `
|
|
31
|
+
insert into hub.faucet_claim (user_id, casino_id, experience_id, currency_key, amount)
|
|
32
|
+
values ($1, $2, $3, $4, $5)
|
|
33
|
+
`,
|
|
34
|
+
values: [
|
|
35
|
+
session.user_id,
|
|
36
|
+
session.casino_id,
|
|
37
|
+
session.experience_id,
|
|
38
|
+
"PLAY",
|
|
39
|
+
CLAIM_AMOUNT,
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
await pgClient.query({
|
|
43
|
+
text: `
|
|
44
|
+
INSERT INTO hub.balance (user_id, experience_id, casino_id, currency_key, amount)
|
|
45
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
46
|
+
ON CONFLICT (user_id, experience_id, casino_id, currency_key) DO UPDATE
|
|
47
|
+
SET amount = balance.amount + EXCLUDED.amount
|
|
48
|
+
`,
|
|
49
|
+
values: [
|
|
50
|
+
session.user_id,
|
|
51
|
+
session.experience_id,
|
|
52
|
+
session.casino_id,
|
|
53
|
+
"PLAY",
|
|
54
|
+
CLAIM_AMOUNT,
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
return object({
|
|
61
|
+
result: $result,
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
HubClaimFaucetPayload: {
|
|
66
|
+
success($data) {
|
|
67
|
+
return $data.get("result");
|
|
68
|
+
},
|
|
69
|
+
query() {
|
|
70
|
+
return constant(true);
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
async function upsertPlayCurrency(pgClient, casinoId) {
|
|
77
|
+
return pgClient.query({
|
|
78
|
+
text: `
|
|
79
|
+
insert into hub.currency (casino_id, key, display_unit_name, display_unit_scale)
|
|
80
|
+
values ($1, 'PLAY', 'tokens', 1)
|
|
81
|
+
on conflict (casino_id, key) do nothing
|
|
82
|
+
`,
|
|
83
|
+
values: [casinoId],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const HubCurrentXPlugin: GraphileConfig.Plugin;
|