@moneypot/hub 1.4.10 → 1.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @moneypot/hub
2
2
 
3
- @moneypot/hub is our official game server that integrates with any number of Moneypot casinos.
3
+ @moneypot/hub is our official GraphQL game server for building games for [MoneyPot.com](https://moneypot.com).
4
4
 
5
5
  - Extend it with custom tables and game logic.
6
6
  - Give it an api key for each controller you've registered on each casino.
@@ -13,7 +13,7 @@ Example implementations:
13
13
 
14
14
  ## Manual
15
15
 
16
- View our docs: https://moneypot.com/docs/hub
16
+ View our docs: <https://docs.moneypot.com>
17
17
 
18
18
  ## Install
19
19
 
@@ -76,4 +76,11 @@ insert into hub.api_key default values returning key;
76
76
 
77
77
  ## Changelog
78
78
 
79
- (Waiting for launch to begin publishing to changelog)
79
+ ### 1.5.x
80
+
81
+ Migrated to Postgraphile beta.52 which has new plugin and polymorphism systems:
82
+
83
+ Read more:
84
+
85
+ - https://www.graphile.org/news/20250607-last-epic-solved/
86
+ - https://grafast.org/grafast/polymorphism
@@ -7,12 +7,14 @@ export const HubBadHashChainErrorPlugin = makeExtendSchemaPlugin(() => {
7
7
  message: String
8
8
  }
9
9
  `,
10
- plans: {
10
+ objects: {
11
11
  HubBadHashChainError: {
12
- __assertStep: ObjectStep,
13
- message($data) {
14
- const $message = access($data, "message");
15
- return $message;
12
+ assertStep: ObjectStep,
13
+ plans: {
14
+ message($data) {
15
+ const $message = access($data, "message");
16
+ return $message;
17
+ },
16
18
  },
17
19
  },
18
20
  },
@@ -18,21 +18,22 @@ export const HubCreateHashChainPlugin = makeExtendSchemaPlugin((build) => {
18
18
  hubCreateHashChain: HubCreateHashChainPayload!
19
19
  }
20
20
  `,
21
- plans: {
21
+ objects: {
22
22
  Mutation: {
23
- hubCreateHashChain: () => {
24
- const $identity = context().get("identity");
25
- const $hashChainId = sideEffect([$identity], ([identity]) => {
26
- if (identity?.kind !== "user") {
27
- throw new GraphQLError("Unauthorized");
28
- }
29
- return withPgPoolTransaction(superuserPool, async (pgClient) => {
30
- await PgAdvisoryLock.forNewHashChain(pgClient, {
31
- userId: identity.session.user_id,
32
- experienceId: identity.session.experience_id,
33
- casinoId: identity.session.casino_id,
34
- });
35
- await pgClient.query(`
23
+ plans: {
24
+ hubCreateHashChain: () => {
25
+ const $identity = context().get("identity");
26
+ const $hashChainId = sideEffect([$identity], ([identity]) => {
27
+ if (identity?.kind !== "user") {
28
+ throw new GraphQLError("Unauthorized");
29
+ }
30
+ return withPgPoolTransaction(superuserPool, async (pgClient) => {
31
+ await PgAdvisoryLock.forNewHashChain(pgClient, {
32
+ userId: identity.session.user_id,
33
+ experienceId: identity.session.experience_id,
34
+ casinoId: identity.session.casino_id,
35
+ });
36
+ await pgClient.query(`
36
37
  UPDATE hub.hash_chain
37
38
  SET active = false
38
39
  WHERE user_id = $1
@@ -40,12 +41,12 @@ export const HubCreateHashChainPlugin = makeExtendSchemaPlugin((build) => {
40
41
  AND casino_id = $3
41
42
  AND active = true
42
43
  `, [
43
- identity.session.user_id,
44
- identity.session.experience_id,
45
- identity.session.casino_id,
46
- ]);
47
- const dbHashChain = await pgClient
48
- .query(`
44
+ identity.session.user_id,
45
+ identity.session.experience_id,
46
+ identity.session.casino_id,
47
+ ]);
48
+ const dbHashChain = await pgClient
49
+ .query(`
49
50
  INSERT INTO hub.hash_chain (
50
51
  user_id,
51
52
  experience_id,
@@ -57,16 +58,16 @@ export const HubCreateHashChainPlugin = makeExtendSchemaPlugin((build) => {
57
58
  VALUES ($1, $2, $3, true, $4, $4)
58
59
  RETURNING *
59
60
  `, [
60
- identity.session.user_id,
61
- identity.session.experience_id,
62
- identity.session.casino_id,
63
- config.HASHCHAINSERVER_MAX_ITERATIONS,
64
- ])
65
- .then(exactlyOneRow);
66
- const terminalHash = await HashCommon.getTerminalHash({
67
- hashChainId: dbHashChain.id,
68
- });
69
- await pgClient.query(`
61
+ identity.session.user_id,
62
+ identity.session.experience_id,
63
+ identity.session.casino_id,
64
+ config.HASHCHAINSERVER_MAX_ITERATIONS,
65
+ ])
66
+ .then(exactlyOneRow);
67
+ const terminalHash = await HashCommon.getTerminalHash({
68
+ hashChainId: dbHashChain.id,
69
+ });
70
+ await pgClient.query(`
70
71
  INSERT INTO hub.hash (
71
72
  hash_chain_id,
72
73
  kind,
@@ -75,17 +76,18 @@ export const HubCreateHashChainPlugin = makeExtendSchemaPlugin((build) => {
75
76
  )
76
77
  VALUES ($1, $2, $3, $4)
77
78
  `, [
78
- dbHashChain.id,
79
- DbHashKind.TERMINAL,
80
- terminalHash,
81
- config.HASHCHAINSERVER_MAX_ITERATIONS,
82
- ]);
83
- return dbHashChain.id;
79
+ dbHashChain.id,
80
+ DbHashKind.TERMINAL,
81
+ terminalHash,
82
+ config.HASHCHAINSERVER_MAX_ITERATIONS,
83
+ ]);
84
+ return dbHashChain.id;
85
+ });
86
+ });
87
+ return object({
88
+ hashChain: hashChainTable.get({ id: $hashChainId }),
84
89
  });
85
- });
86
- return object({
87
- hashChain: hashChainTable.get({ id: $hashChainId }),
88
- });
90
+ },
89
91
  },
90
92
  },
91
93
  },
@@ -12,18 +12,19 @@ export const HubUserActiveHashChainPlugin = makeExtendSchemaPlugin((build) => {
12
12
  activeHashChain: HubHashChain
13
13
  }
14
14
  `,
15
- plans: {
15
+ objects: {
16
16
  HubUser: {
17
- activeHashChain: ($record) => {
18
- const $identity = context().get("identity");
19
- const $hashChainId = withPgClient(hashChainTable.executor, object({ userId: $record.get("id"), identity: $identity }), async (pgClient, { userId, identity }) => {
20
- if (identity?.kind !== "user") {
21
- return null;
22
- }
23
- const { session } = identity;
24
- const activeHashChain = await pgClient
25
- .query({
26
- text: `
17
+ plans: {
18
+ activeHashChain: ($record) => {
19
+ const $identity = context().get("identity");
20
+ const $hashChainId = withPgClient(hashChainTable.executor, object({ userId: $record.get("id"), identity: $identity }), async (pgClient, { userId, identity }) => {
21
+ if (identity?.kind !== "user") {
22
+ return null;
23
+ }
24
+ const { session } = identity;
25
+ const activeHashChain = await pgClient
26
+ .query({
27
+ text: `
27
28
  select id
28
29
  from hub.hash_chain
29
30
  where user_id = $1
@@ -33,12 +34,13 @@ export const HubUserActiveHashChainPlugin = makeExtendSchemaPlugin((build) => {
33
34
  order by id desc
34
35
  limit 1
35
36
  `,
36
- values: [userId, session.experience_id, session.casino_id],
37
- })
38
- .then(maybeOneRow);
39
- return activeHashChain?.id ?? null;
40
- });
41
- return hashChainTable.get({ id: inhibitOnNull($hashChainId) });
37
+ values: [userId, session.experience_id, session.casino_id],
38
+ })
39
+ .then(maybeOneRow);
40
+ return activeHashChain?.id ?? null;
41
+ });
42
+ return hashChainTable.get({ id: inhibitOnNull($hashChainId) });
43
+ },
42
44
  },
43
45
  },
44
46
  },
@@ -1,7 +1,23 @@
1
1
  import { Express } from "express";
2
2
  import { Logger } from "./logger.js";
3
+ import { PluginIdentity } from "./server/graphile.config.js";
4
+ declare global {
5
+ namespace Grafast {
6
+ interface Context {
7
+ identity?: PluginIdentity;
8
+ abortSignal: AbortSignal;
9
+ }
10
+ }
11
+ }
12
+ declare global {
13
+ namespace GraphileBuild {
14
+ interface SchemaOptions {
15
+ pgDeletedColumnName?: string;
16
+ }
17
+ }
18
+ }
3
19
  export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
4
- export { defaultPlugins, type PluginContext, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
20
+ export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
5
21
  export type ServerOptions = {
6
22
  configureApp?: (app: Express) => void;
7
23
  plugins?: readonly GraphileConfig.Plugin[];
@@ -43,115 +43,117 @@ export const HubAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
43
43
  hubAddCasino(input: HubAddCasinoInput!): HubAddCasinoPayload
44
44
  }
45
45
  `,
46
- plans: {
46
+ objects: {
47
47
  Mutation: {
48
- hubAddCasino(_, { $input }) {
49
- const $identity = context().get("identity");
50
- const $abortSignal = context().get("abortSignal");
51
- const $casinoId = sideEffect([$input, $identity, $abortSignal], ([input, identity, abortSignal]) => {
52
- return withPgPoolTransaction(superuserPool, async (pgClient) => {
53
- if (identity?.kind !== "operator") {
54
- throw new GraphQLError("Unauthorized");
55
- }
56
- assert(is(input));
57
- const { name, baseUrl, graphqlUrl, apiKey } = input;
58
- const graphqlClient = new GraphQLClient(graphqlUrl, {
59
- headers: {
60
- Authorization: `apikey:${apiKey}`,
61
- },
62
- });
63
- console.log(`[hubAddCasino] Making request to ${graphqlUrl}`);
64
- const result = await graphqlClient
65
- .request(GET_CURRENT_CONTROLLER)
66
- .catch((e) => {
67
- if (e.cause?.code === "ECONNREFUSED" ||
68
- e.cause?.code === "ENOTFOUND") {
69
- throw new GraphQLError(`Cannot connect to graphqlUrl`);
48
+ plans: {
49
+ hubAddCasino(_, { $input }) {
50
+ const $identity = context().get("identity");
51
+ const $abortSignal = context().get("abortSignal");
52
+ const $casinoId = sideEffect([$input, $identity, $abortSignal], ([input, identity, abortSignal]) => {
53
+ return withPgPoolTransaction(superuserPool, async (pgClient) => {
54
+ if (identity?.kind !== "operator") {
55
+ throw new GraphQLError("Unauthorized");
70
56
  }
71
- throw e;
72
- });
73
- if (!result || !result.currentController) {
74
- throw new GraphQLError("Invalid API key for your casino controller. Go to your controller on the casino website and double check.");
75
- }
76
- let casino;
77
- try {
78
- casino = await pgClient
79
- .query({
80
- text: `
57
+ assert(is(input));
58
+ const { name, baseUrl, graphqlUrl, apiKey } = input;
59
+ const graphqlClient = new GraphQLClient(graphqlUrl, {
60
+ headers: {
61
+ Authorization: `apikey:${apiKey}`,
62
+ },
63
+ });
64
+ console.log(`[hubAddCasino] Making request to ${graphqlUrl}`);
65
+ const result = await graphqlClient
66
+ .request(GET_CURRENT_CONTROLLER)
67
+ .catch((e) => {
68
+ if (e.cause?.code === "ECONNREFUSED" ||
69
+ e.cause?.code === "ENOTFOUND") {
70
+ throw new GraphQLError(`Cannot connect to graphqlUrl`);
71
+ }
72
+ throw e;
73
+ });
74
+ if (!result || !result.currentController) {
75
+ throw new GraphQLError("Invalid API key for your casino controller. Go to your controller on the casino website and double check.");
76
+ }
77
+ let casino;
78
+ try {
79
+ casino = await pgClient
80
+ .query({
81
+ text: `
81
82
  INSERT INTO hub.casino(name, base_url, graphql_url)
82
83
  VALUES($1, $2, $3)
83
84
  returning id
84
85
  `,
85
- values: [name, baseUrl, graphqlUrl],
86
- })
87
- .then((res) => {
88
- console.log("res", res.rows);
89
- return res;
90
- })
91
- .then(exactlyOneRow);
92
- }
93
- catch (e) {
94
- if (e instanceof Error &&
95
- "code" in e &&
96
- e.code === "23505" &&
97
- "constraint" in e) {
98
- switch (e.constraint) {
99
- case "casino_graphql_url_idx":
100
- throw new GraphQLError("Casino with that graphqlUrl already exists");
101
- case "casino_base_url_idx":
102
- throw new GraphQLError("Casino with that baseUrl already exists");
103
- default:
104
- throw new GraphQLError(`Duplicate constraint violation: ${e.constraint}`);
86
+ values: [name, baseUrl, graphqlUrl],
87
+ })
88
+ .then((res) => {
89
+ console.log("res", res.rows);
90
+ return res;
91
+ })
92
+ .then(exactlyOneRow);
93
+ }
94
+ catch (e) {
95
+ if (e instanceof Error &&
96
+ "code" in e &&
97
+ e.code === "23505" &&
98
+ "constraint" in e) {
99
+ switch (e.constraint) {
100
+ case "casino_graphql_url_idx":
101
+ throw new GraphQLError("Casino with that graphqlUrl already exists");
102
+ case "casino_base_url_idx":
103
+ throw new GraphQLError("Casino with that baseUrl already exists");
104
+ default:
105
+ throw new GraphQLError(`Duplicate constraint violation: ${e.constraint}`);
106
+ }
105
107
  }
108
+ logger.error("Error adding casino", e);
109
+ throw e;
106
110
  }
107
- logger.error("Error adding casino", e);
108
- throw e;
109
- }
110
- await pgClient.query({
111
- text: `
111
+ await pgClient.query({
112
+ text: `
112
113
  INSERT INTO hub.casino_secret(id, controller_id, api_key)
113
114
  VALUES($1, $2, $3)
114
115
  `,
115
- values: [casino.id, result.currentController.id, apiKey],
116
- });
117
- const currencies = result.allCurrencies?.nodes.flatMap((x) => x || []) || [];
118
- await upsertCurrencies(pgClient, {
119
- casinoId: casino.id,
120
- currencies,
121
- });
122
- await pgClient.query({
123
- text: `
116
+ values: [casino.id, result.currentController.id, apiKey],
117
+ });
118
+ const currencies = result.allCurrencies?.nodes.flatMap((x) => x || []) || [];
119
+ await upsertCurrencies(pgClient, {
120
+ casinoId: casino.id,
121
+ currencies,
122
+ });
123
+ await pgClient.query({
124
+ text: `
124
125
  INSERT INTO hub.bankroll (casino_id, currency_key)
125
126
  SELECT casino_id, key
126
127
  FROM hub.currency
127
128
  WHERE casino_id = $1
128
129
  `,
129
- values: [casino.id],
130
- });
131
- await pgClient.query({
132
- text: `
130
+ values: [casino.id],
131
+ });
132
+ await pgClient.query({
133
+ text: `
133
134
  UPDATE hub.bankroll
134
135
  SET amount = 1000000
135
136
  WHERE casino_id = $1 AND currency_key = 'HOUSE'
136
137
  `,
137
- values: [casino.id],
138
+ values: [casino.id],
139
+ });
140
+ logger.info(`Fetching JWKS for new casino from ${graphqlUrl}...`);
141
+ await jwtService.refreshCasinoJwksTask(pgClient, {
142
+ graphqlClient,
143
+ casinoId: casino.id,
144
+ });
145
+ startTransferProcessor({
146
+ casinoId: casino.id,
147
+ signal: abortSignal,
148
+ });
149
+ return casino.id;
138
150
  });
139
- logger.info(`Fetching JWKS for new casino from ${graphqlUrl}...`);
140
- await jwtService.refreshCasinoJwksTask(pgClient, {
141
- graphqlClient,
142
- casinoId: casino.id,
143
- });
144
- startTransferProcessor({
145
- casinoId: casino.id,
146
- signal: abortSignal,
147
- });
148
- return casino.id;
149
151
  });
150
- });
151
- return object({
152
- casino: casinoTable.get({ id: $casinoId }),
153
- query: constant(true),
154
- });
152
+ return object({
153
+ casino: casinoTable.get({ id: $casinoId }),
154
+ query: constant(true),
155
+ });
156
+ },
155
157
  },
156
158
  },
157
159
  },