@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,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 CaasAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
|
|
27
|
+
const casinoTable = build.input.pgRegistry.pgResources.caas_casino;
|
|
28
|
+
return {
|
|
29
|
+
typeDefs: gql `
|
|
30
|
+
input CaasAddCasinoInput {
|
|
31
|
+
name: String!
|
|
32
|
+
baseUrl: String!
|
|
33
|
+
graphqlUrl: String!
|
|
34
|
+
apiKey: String!
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type CaasAddCasinoPayload {
|
|
38
|
+
casino: CaasCasino
|
|
39
|
+
query: Query
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
extend type Mutation {
|
|
43
|
+
caasAddCasino(input: CaasAddCasinoInput!): CaasAddCasinoPayload
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
plans: {
|
|
47
|
+
Mutation: {
|
|
48
|
+
caasAddCasino(_, { $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(`[caasAddCasino] 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 caas.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 caas.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 caas.bankroll (casino_id, currency_key)
|
|
127
|
+
SELECT casino_id, key
|
|
128
|
+
FROM caas.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 CaasAuthenticatePlugin: 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 CaasAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
13
|
+
return {
|
|
14
|
+
typeDefs: gql `
|
|
15
|
+
input CaasAuthenticateInput {
|
|
16
|
+
casinoBaseUrl: String!
|
|
17
|
+
userToken: String!
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type CaasAuthenticateSuccess {
|
|
21
|
+
experienceId: UUID!
|
|
22
|
+
sessionKey: UUID!
|
|
23
|
+
userId: UUID!
|
|
24
|
+
uname: String!
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type CaasAuthenticatePayload {
|
|
28
|
+
query: Query
|
|
29
|
+
success: CaasAuthenticateSuccess
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
extend type Mutation {
|
|
33
|
+
caasAuthenticate(input: CaasAuthenticateInput!): CaasAuthenticatePayload
|
|
34
|
+
}
|
|
35
|
+
`,
|
|
36
|
+
plans: {
|
|
37
|
+
Mutation: {
|
|
38
|
+
caasAuthenticate(_, { $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 caas.casino c
|
|
50
|
+
LEFT JOIN caas.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(`[caasAuthenticate] 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 caas.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 caas.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 caas.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 CaasBalanceAlertPlugin: 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 CaasBalanceAlertPlugin = makeExtendSchemaPlugin(() => {
|
|
5
|
+
return {
|
|
6
|
+
typeDefs: gql `
|
|
7
|
+
extend type Subscription {
|
|
8
|
+
caasBalanceAlert: CaasBalanceAlertPayload
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type CaasBalanceAlertPayload {
|
|
12
|
+
currencyKey: String
|
|
13
|
+
}
|
|
14
|
+
`,
|
|
15
|
+
plans: {
|
|
16
|
+
Subscription: {
|
|
17
|
+
caasBalanceAlert: {
|
|
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 `caas: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
|
+
CaasBalanceAlertPayload: {
|
|
37
|
+
currencyKey($event) {
|
|
38
|
+
return $event.get("currency_key");
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CaasClaimFaucetPlugin: 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 CaasClaimFaucetPlugin = makeExtendSchemaPlugin(() => {
|
|
7
|
+
return {
|
|
8
|
+
typeDefs: gql `
|
|
9
|
+
type CaasClaimFaucetPayload {
|
|
10
|
+
success: Boolean!
|
|
11
|
+
query: Query
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
extend type Mutation {
|
|
15
|
+
caasClaimFaucet: CaasClaimFaucetPayload
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
plans: {
|
|
19
|
+
Mutation: {
|
|
20
|
+
caasClaimFaucet() {
|
|
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 caas.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 caas.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
|
+
CaasClaimFaucetPayload: {
|
|
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 caas.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 CaasCurrentXPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { gql, makeExtendSchemaPlugin } from "graphile-utils";
|
|
2
|
+
import { context, inhibitOnNull, lambda } from "postgraphile/grafast";
|
|
3
|
+
export const CaasCurrentXPlugin = makeExtendSchemaPlugin((build) => {
|
|
4
|
+
const userTable = build.input.pgRegistry.pgResources.caas_user;
|
|
5
|
+
const casinoTable = build.input.pgRegistry.pgResources.caas_casino;
|
|
6
|
+
const experienceTable = build.input.pgRegistry.pgResources.caas_experience;
|
|
7
|
+
const sessionTable = build.input.pgRegistry.pgResources.caas_session;
|
|
8
|
+
return {
|
|
9
|
+
typeDefs: gql `
|
|
10
|
+
extend type Query {
|
|
11
|
+
caasCurrentUser: CaasUser
|
|
12
|
+
caasCurrentCasino: CaasCasino
|
|
13
|
+
caasCurrentExperience: CaasExperience
|
|
14
|
+
caasCurrentSession: CaasSession
|
|
15
|
+
}
|
|
16
|
+
`,
|
|
17
|
+
plans: {
|
|
18
|
+
Query: {
|
|
19
|
+
caasCurrentUser() {
|
|
20
|
+
const $identity = context().get("identity");
|
|
21
|
+
const $userId = lambda($identity, (identity) => {
|
|
22
|
+
if (identity?.kind === "user") {
|
|
23
|
+
return identity.session.user_id;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
});
|
|
27
|
+
return userTable.get({ id: inhibitOnNull($userId) });
|
|
28
|
+
},
|
|
29
|
+
caasCurrentCasino() {
|
|
30
|
+
const $identity = context().get("identity");
|
|
31
|
+
const $casinoId = lambda($identity, (identity) => {
|
|
32
|
+
if (identity?.kind === "user") {
|
|
33
|
+
return identity.session.casino_id;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
});
|
|
37
|
+
return casinoTable.get({ id: inhibitOnNull($casinoId) });
|
|
38
|
+
},
|
|
39
|
+
caasCurrentExperience() {
|
|
40
|
+
const $identity = context().get("identity");
|
|
41
|
+
const $experienceId = lambda($identity, (identity) => {
|
|
42
|
+
if (identity?.kind === "user") {
|
|
43
|
+
return identity.session.experience_id;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
});
|
|
47
|
+
return experienceTable.get({ id: inhibitOnNull($experienceId) });
|
|
48
|
+
},
|
|
49
|
+
caasCurrentSession() {
|
|
50
|
+
const $identity = context().get("identity");
|
|
51
|
+
const $sessionId = lambda($identity, (identity) => {
|
|
52
|
+
if (identity?.kind === "user") {
|
|
53
|
+
return identity.session.session_id;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
});
|
|
57
|
+
return sessionTable.get({ id: inhibitOnNull($sessionId) });
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CaasPrefixPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const CaasPrefixPlugin = {
|
|
2
|
+
name: "CaasPrefixPlugin",
|
|
3
|
+
version: "1.0.0",
|
|
4
|
+
after: ["PgTablesPlugin"],
|
|
5
|
+
inflection: {
|
|
6
|
+
replace: {
|
|
7
|
+
_schemaPrefix(previous, options, { pgNamespace, serviceName, }) {
|
|
8
|
+
const pgService = options.pgServices?.find((db) => db.name === serviceName);
|
|
9
|
+
const databasePrefix = serviceName === "main" ? "" : `${serviceName}_`;
|
|
10
|
+
let schemaPrefix;
|
|
11
|
+
if (pgNamespace.nspname === "caas" ||
|
|
12
|
+
pgNamespace.nspname.startsWith("caas_")) {
|
|
13
|
+
schemaPrefix = `${pgNamespace.nspname}_`;
|
|
14
|
+
}
|
|
15
|
+
else if (pgNamespace.nspname === pgService?.schemas?.[0]) {
|
|
16
|
+
schemaPrefix = "";
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
schemaPrefix = `${pgNamespace.nspname}_`;
|
|
20
|
+
}
|
|
21
|
+
return `${databasePrefix}${schemaPrefix}`;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CaasUserBalanceByCurrencyPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { access, context, loadOne, object, } from "postgraphile/grafast";
|
|
2
|
+
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
|
+
import { superuserPool } from "../db/index.js";
|
|
4
|
+
import { pgSelectSingleFromRecord, } from "postgraphile/@dataplan/pg";
|
|
5
|
+
export const CaasUserBalanceByCurrencyPlugin = makeExtendSchemaPlugin((build) => {
|
|
6
|
+
const balances = build.input.pgRegistry.pgResources.caas_balance;
|
|
7
|
+
return {
|
|
8
|
+
typeDefs: gql `
|
|
9
|
+
extend type CaasUser {
|
|
10
|
+
balanceByCurrency(currency: String!): CaasBalance
|
|
11
|
+
}
|
|
12
|
+
`,
|
|
13
|
+
plans: {
|
|
14
|
+
CaasUser: {
|
|
15
|
+
balanceByCurrency: ($record, { $currency }) => {
|
|
16
|
+
const $identity = context().get("identity");
|
|
17
|
+
const $params = object({
|
|
18
|
+
currency: $currency,
|
|
19
|
+
targetUserId: $record.get("id"),
|
|
20
|
+
casino_id: access($identity, ["session", "casino_id"]),
|
|
21
|
+
experience_id: access($identity, ["session", "experience_id"]),
|
|
22
|
+
});
|
|
23
|
+
const $balance = loadOne($params, batchGetUserBalanceByCurrency);
|
|
24
|
+
return pgSelectSingleFromRecord(balances, $balance);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
async function batchGetUserBalanceByCurrency(paramsArray) {
|
|
31
|
+
const values = [];
|
|
32
|
+
const valuePlaceholders = [];
|
|
33
|
+
paramsArray.forEach((p, index) => {
|
|
34
|
+
const baseIndex = index * 4 + 1;
|
|
35
|
+
valuePlaceholders.push(`($${baseIndex}, $${baseIndex + 1}::uuid, $${baseIndex + 2}::uuid, $${baseIndex + 3}::uuid)`);
|
|
36
|
+
values.push(p.currency, p.targetUserId, p.casino_id, p.experience_id);
|
|
37
|
+
});
|
|
38
|
+
const sql = `
|
|
39
|
+
SELECT b.*
|
|
40
|
+
FROM caas.balance b
|
|
41
|
+
JOIN (
|
|
42
|
+
VALUES
|
|
43
|
+
${valuePlaceholders.join(",\n ")}
|
|
44
|
+
) AS vals(currency_key, user_id, casino_id, experience_id)
|
|
45
|
+
ON b.currency_key = vals.currency_key
|
|
46
|
+
AND b.user_id = vals.user_id
|
|
47
|
+
AND b.casino_id = vals.casino_id
|
|
48
|
+
AND b.experience_id = vals.experience_id
|
|
49
|
+
`;
|
|
50
|
+
const { rows } = await superuserPool.query(sql, values);
|
|
51
|
+
return paramsArray.map((p) => rows.find((row) => row.currency_key === p.currency &&
|
|
52
|
+
row.user_id === p.targetUserId &&
|
|
53
|
+
row.casino_id === p.casino_id &&
|
|
54
|
+
row.experience_id === p.experience_id));
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CaasWithdrawPlugin: GraphileConfig.Plugin;
|