@moneypot/hub 1.18.0-dev.1 → 1.18.0-dev.3

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.
@@ -0,0 +1,7 @@
1
+ import { RiskPolicy } from "./risk-policy.js";
2
+ export type CustomGameConfig = {
3
+ riskPolicy: RiskPolicy;
4
+ };
5
+ export type CustomGameConfigMap<CustomGameKind extends string> = {
6
+ [kind in CustomGameKind]: CustomGameConfig;
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -18,6 +18,8 @@ declare global {
18
18
  }
19
19
  }
20
20
  export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
21
+ export { HubRiskLimitsPlugin } from "./plugins/hub-risk-limits.js";
22
+ export { type CustomGameConfig, type CustomGameConfigMap, } from "./custom-game-config.js";
21
23
  export { validateRisk, type RiskPolicy, type RiskPolicyArgs, type RiskLimits, } from "./risk-policy.js";
22
24
  export type PluginContext = Grafast.Context;
23
25
  export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
@@ -33,6 +35,7 @@ export type ServerOptions = {
33
35
  userDatabaseMigrationsPath?: string;
34
36
  enableChat?: boolean;
35
37
  enablePlayground?: boolean;
38
+ port?: number;
36
39
  };
37
40
  export declare function runMigrations(options: {
38
41
  userDatabaseMigrationsPath?: string;
package/dist/src/index.js CHANGED
@@ -7,6 +7,7 @@ import { join } from "path";
7
7
  import { logger } from "./logger.js";
8
8
  import { createServerContext, closeServerContext, } from "./context.js";
9
9
  export { MakeOutcomeBetPlugin, } from "./plugins/hub-make-outcome-bet.js";
10
+ export { HubRiskLimitsPlugin } from "./plugins/hub-risk-limits.js";
10
11
  export { validateRisk, } from "./risk-policy.js";
11
12
  export { defaultPlugins, } from "./server/graphile.config.js";
12
13
  export async function runMigrations(options) {
@@ -28,6 +29,7 @@ export async function runMigrations(options) {
28
29
  pgClient,
29
30
  dirname: join(import.meta.dirname, "pg-versions"),
30
31
  schemaName: "hub_core_versions",
32
+ silent: process.env.NODE_ENV === "test",
31
33
  });
32
34
  }
33
35
  catch (e) {
@@ -43,6 +45,7 @@ export async function runMigrations(options) {
43
45
  pgClient,
44
46
  dirname: options.userDatabaseMigrationsPath,
45
47
  schemaName: "hub_user_versions",
48
+ silent: process.env.NODE_ENV === "test",
46
49
  });
47
50
  }
48
51
  }
@@ -98,6 +101,7 @@ export async function startAndListen(options) {
98
101
  context,
99
102
  enableChat: options.enableChat ?? true,
100
103
  enablePlayground: options.enablePlayground ?? true,
104
+ port: options.port ?? config.PORT,
101
105
  });
102
106
  const gracefulShutdown = async ({ exit = true } = {}) => {
103
107
  if (isShuttingDown) {
@@ -128,9 +132,9 @@ export async function startAndListen(options) {
128
132
  process.on("SIGINT", gracefulShutdown);
129
133
  process.on("SIGTERM", gracefulShutdown);
130
134
  }
131
- return hubServer.listen().then(() => {
135
+ return hubServer.listen().then(({ port }) => {
132
136
  return {
133
- port: config.PORT,
137
+ port,
134
138
  stop: async () => {
135
139
  await gracefulShutdown({ exit: false });
136
140
  },
@@ -33,10 +33,10 @@ export type OutcomeBetConfig = {
33
33
  initializeMetadataFromUntrustedUserInput?: (input: Input) => Result<Metadata, string>;
34
34
  finalizeMetadata?: (validatedMetadata: Metadata, data: FinalizeMetadataData) => Metadata;
35
35
  };
36
- export type OutcomeBetConfigMap<BetKind extends string> = {
37
- [betKind in BetKind]: OutcomeBetConfig;
36
+ export type OutcomeBetConfigMap<OutcomeBetKind extends string> = {
37
+ [kind in OutcomeBetKind]: OutcomeBetConfig;
38
38
  };
39
- export declare function MakeOutcomeBetPlugin<BetKind extends string>({ betConfigs }: {
40
- betConfigs: OutcomeBetConfigMap<BetKind>;
39
+ export declare function MakeOutcomeBetPlugin<OutcomeBetKind extends string>({ outcomeBetConfigs, }: {
40
+ outcomeBetConfigs: OutcomeBetConfigMap<OutcomeBetKind>;
41
41
  }): GraphileConfig.Plugin;
42
42
  export {};
@@ -2,7 +2,7 @@ import { access, context, object, ObjectStep, sideEffect, } from "postgraphile/g
2
2
  import { gql, extendSchema } from "postgraphile/utils";
3
3
  import * as z from "zod/v4";
4
4
  import { GraphQLError } from "graphql";
5
- import { DbHashKind, dbGetHouseBankrolls, dbLockHouseBankroll, dbLockPlayerBalance, exactlyOneRow, maybeOneRow, withPgPoolTransaction, } from "../db/index.js";
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";
@@ -68,18 +68,18 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
68
68
  .function()
69
69
  .optional(),
70
70
  }));
71
- export function MakeOutcomeBetPlugin({ betConfigs }) {
72
- BetConfigsSchema.parse(betConfigs);
73
- const betKinds = Object.keys(betConfigs);
71
+ export function MakeOutcomeBetPlugin({ outcomeBetConfigs, }) {
72
+ BetConfigsSchema.parse(outcomeBetConfigs);
73
+ const outcomeBetKinds = Object.keys(outcomeBetConfigs);
74
74
  return extendSchema((build) => {
75
75
  const outcomeBetTable = build.input.pgRegistry.pgResources.hub_outcome_bet;
76
76
  const typeDefs = gql `
77
- enum BetKind {
78
- ${betKinds.join("\n")}
77
+ enum OutcomeBetKind {
78
+ ${outcomeBetKinds.join("\n")}
79
79
  }
80
80
 
81
81
  input HubMakeOutcomeBetInput {
82
- kind: BetKind!
82
+ kind: OutcomeBetKind!
83
83
  wager: Int!
84
84
  currency: String!
85
85
  outcomes: [HubOutcomeInput!]!
@@ -106,58 +106,10 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
106
106
  extend type Mutation {
107
107
  hubMakeOutcomeBet(input: HubMakeOutcomeBetInput!): HubMakeOutcomeBetPayload
108
108
  }
109
-
110
- type HubRiskLimit {
111
- maxPayout: Float!
112
- maxWager: Float
113
- }
114
-
115
- type HubRiskLimitWithCurrency {
116
- currency: String!
117
- maxPayout: Float!
118
- maxWager: Float
119
- }
120
-
121
- extend type Query {
122
- hubRiskLimits(betKind: BetKind!): [HubRiskLimitWithCurrency!]!
123
- }
124
109
  `;
125
110
  return {
126
111
  typeDefs,
127
112
  objects: {
128
- Query: {
129
- plans: {
130
- hubRiskLimits: (_, { $betKind }) => {
131
- const $identity = context().get("identity");
132
- const $superuserPool = context().get("superuserPool");
133
- const $result = sideEffect([$identity, $superuserPool, $betKind], async ([identity, superuserPool, betKind]) => {
134
- if (identity?.kind !== "user") {
135
- throw new GraphQLError("Unauthorized");
136
- }
137
- const betConfig = betConfigs[betKind];
138
- if (!betConfig) {
139
- throw new GraphQLError(`Invalid bet kind`);
140
- }
141
- const dbHouseBankrolls = await dbGetHouseBankrolls(superuserPool, {
142
- casinoId: identity.session.casino_id,
143
- });
144
- const limitsWithCurrency = dbHouseBankrolls.map((bankroll) => {
145
- const limits = betConfig.riskPolicy({
146
- type: "get-limits",
147
- currency: bankroll.currency_key,
148
- bankroll: bankroll.amount,
149
- });
150
- return {
151
- currency: bankroll.currency_key,
152
- ...limits,
153
- };
154
- });
155
- return limitsWithCurrency;
156
- });
157
- return $result;
158
- },
159
- },
160
- },
161
113
  Mutation: {
162
114
  plans: {
163
115
  hubMakeOutcomeBet: (_, { $input }) => {
@@ -168,10 +120,10 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
168
120
  throw new GraphQLError("Unauthorized");
169
121
  }
170
122
  let input;
171
- let betKind;
123
+ let outcomeBetKind;
172
124
  try {
173
125
  input = InputSchema.parse(rawInput);
174
- betKind = BetKindSchema.parse(rawInput.kind);
126
+ outcomeBetKind = BetKindSchema.parse(rawInput.kind);
175
127
  }
176
128
  catch (e) {
177
129
  if (e instanceof z.ZodError) {
@@ -183,9 +135,9 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
183
135
  input.currency !== "HOUSE") {
184
136
  throw new GraphQLError("Playground users can only bet with HOUSE currency");
185
137
  }
186
- const betConfig = betConfigs[betKind];
138
+ const betConfig = outcomeBetConfigs[outcomeBetKind];
187
139
  if (!betConfig) {
188
- throw new GraphQLError(`Invalid bet kind`);
140
+ throw new GraphQLError(`Invalid outcome bet kind`);
189
141
  }
190
142
  if (!betConfig.allowLossBeyondWager) {
191
143
  const minProfit = Math.min(...input.outcomes.map((o) => o.profit));
@@ -496,17 +448,6 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
496
448
  },
497
449
  },
498
450
  },
499
- HubRiskLimit: {
500
- assertStep: ObjectStep,
501
- plans: {
502
- maxWager($data) {
503
- return access($data, "maxWager");
504
- },
505
- maxPayout($data) {
506
- return access($data, "maxPayout");
507
- },
508
- },
509
- },
510
451
  HubMakeOutcomeBetPayload: {
511
452
  assertStep: ObjectStep,
512
453
  plans: {
@@ -0,0 +1,6 @@
1
+ import { OutcomeBetConfigMap } from "./hub-make-outcome-bet.js";
2
+ import { CustomGameConfigMap } from "../custom-game-config.js";
3
+ export declare function HubRiskLimitsPlugin<OutcomeBetKind extends string, CustomGameKind extends string = never>({ outcomeBetConfigs, customGameConfigs, }: {
4
+ outcomeBetConfigs: OutcomeBetConfigMap<OutcomeBetKind>;
5
+ customGameConfigs?: CustomGameConfigMap<CustomGameKind>;
6
+ }): GraphileConfig.Plugin;
@@ -0,0 +1,124 @@
1
+ import { context, sideEffect, access } from "postgraphile/grafast";
2
+ import { gql, extendSchema } from "postgraphile/utils";
3
+ import { GraphQLError } from "graphql";
4
+ import { dbGetHouseBankrolls } from "../db/index.js";
5
+ export function HubRiskLimitsPlugin({ outcomeBetConfigs, customGameConfigs, }) {
6
+ const outcomeBetKinds = Object.keys(outcomeBetConfigs);
7
+ const customGameKinds = customGameConfigs
8
+ ? Object.keys(customGameConfigs)
9
+ : [];
10
+ if (customGameConfigs) {
11
+ const outcomeBetKindSet = new Set(outcomeBetKinds);
12
+ for (const kind of customGameKinds) {
13
+ if (outcomeBetKindSet.has(kind)) {
14
+ throw new Error(`Key collision: "${kind}" exists in both outcomeBetConfigs and customGameConfigs`);
15
+ }
16
+ }
17
+ }
18
+ const anyGameKinds = [...outcomeBetKinds, ...customGameKinds];
19
+ const mergedConfigs = {};
20
+ for (const kind of outcomeBetKinds) {
21
+ mergedConfigs[kind] = outcomeBetConfigs[kind];
22
+ }
23
+ if (customGameConfigs) {
24
+ for (const kind of customGameKinds) {
25
+ mergedConfigs[kind] = customGameConfigs[kind];
26
+ }
27
+ }
28
+ return extendSchema((build) => {
29
+ const typeDefs = gql `
30
+ enum AnyGameKind {
31
+ ${anyGameKinds.join("\n")}
32
+ }
33
+
34
+ ${customGameKinds.length > 0
35
+ ? `enum CustomGameKind {
36
+ ${customGameKinds.join("\n")}
37
+ }`
38
+ : ""}
39
+
40
+ type HubRiskLimit {
41
+ maxPayout: Float!
42
+ }
43
+
44
+ type HubBulkRiskLimit {
45
+ gameKind: AnyGameKind!
46
+ currency: String!
47
+ maxPayout: Float!
48
+ }
49
+
50
+ extend type Query {
51
+ hubRiskLimits(gameKinds: [AnyGameKind!]!): [HubBulkRiskLimit!]!
52
+ }
53
+ `;
54
+ return {
55
+ typeDefs,
56
+ objects: {
57
+ Query: {
58
+ plans: {
59
+ hubRiskLimits: (_, { $gameKinds }) => {
60
+ const $identity = context().get("identity");
61
+ const $superuserPool = context().get("superuserPool");
62
+ const $result = sideEffect([$identity, $superuserPool, $gameKinds], async ([identity, superuserPool, inputGameKinds]) => {
63
+ if (identity?.kind !== "user") {
64
+ throw new GraphQLError("Unauthorized");
65
+ }
66
+ if (inputGameKinds.length > 10) {
67
+ throw new GraphQLError("Maximum 10 game kinds allowed");
68
+ }
69
+ if (new Set(inputGameKinds).size !== inputGameKinds.length) {
70
+ throw new GraphQLError("Duplicate game kinds not allowed");
71
+ }
72
+ for (const kind of inputGameKinds) {
73
+ if (!mergedConfigs[kind]) {
74
+ throw new GraphQLError(`Invalid game kind: ${kind}`);
75
+ }
76
+ }
77
+ const dbHouseBankrolls = await dbGetHouseBankrolls(superuserPool, {
78
+ casinoId: identity.session.casino_id,
79
+ });
80
+ const limits = inputGameKinds.flatMap((gameKind) => {
81
+ const config = mergedConfigs[gameKind];
82
+ return dbHouseBankrolls.map((bankroll) => {
83
+ const riskLimits = config.riskPolicy({
84
+ type: "get-limits",
85
+ currency: bankroll.currency_key,
86
+ bankroll: bankroll.amount,
87
+ });
88
+ return {
89
+ gameKind,
90
+ currency: bankroll.currency_key,
91
+ maxPayout: riskLimits.maxPayout,
92
+ };
93
+ });
94
+ });
95
+ return limits;
96
+ });
97
+ return $result;
98
+ },
99
+ },
100
+ },
101
+ HubRiskLimit: {
102
+ plans: {
103
+ maxPayout($data) {
104
+ return access($data, "maxPayout");
105
+ },
106
+ },
107
+ },
108
+ HubBulkRiskLimit: {
109
+ plans: {
110
+ gameKind($data) {
111
+ return access($data, "gameKind");
112
+ },
113
+ currency($data) {
114
+ return access($data, "currency");
115
+ },
116
+ maxPayout($data) {
117
+ return access($data, "maxPayout");
118
+ },
119
+ },
120
+ },
121
+ },
122
+ };
123
+ }, "HubRiskLimitsPlugin");
124
+ }
@@ -1,7 +1 @@
1
- import * as pg from "pg";
2
- import { GraphQLClient } from "graphql-request";
3
- export declare function processWithdrawalRequests({ casinoId, graphqlClient, pool, }: {
4
- casinoId: string;
5
- graphqlClient: GraphQLClient;
6
- pool: pg.Pool;
7
- }): Promise<void>;
1
+ export {};
@@ -1,146 +1 @@
1
- import { assert } from "tsafe";
2
- import { TransferStatusKind } from "./__generated__/graphql.js";
3
- import { withPgPoolTransaction } from "./db/index.js";
4
- import { maybeOneRow, exactlyOneRow } from "./db/util.js";
5
- import { START_PENDING_EXPERIENCE_TRANSFER } from "./graphql-queries.js";
6
- import { logger } from "./logger.js";
7
- async function processWithdrawalRequest({ requestId, graphqlClient, pool, }) {
8
- return withPgPoolTransaction(pool, async (pgClient) => {
9
- const dbWithdrawalRequest = await pgClient
10
- .query({
11
- text: `
12
- select *
13
- from hub.withdrawal_request
14
- where id = $1
15
-
16
- FOR UPDATE
17
- `,
18
- values: [requestId],
19
- })
20
- .then(maybeOneRow);
21
- if (!dbWithdrawalRequest) {
22
- throw new Error("Withdrawal request not found");
23
- }
24
- if (dbWithdrawalRequest.mp_transfer_id) {
25
- return;
26
- }
27
- const dbUser = await pgClient
28
- .query({
29
- text: `select * from hub.user where id = $1`,
30
- values: [dbWithdrawalRequest.user_id],
31
- })
32
- .then(exactlyOneRow);
33
- const dbExperience = await pgClient
34
- .query({
35
- text: `select * from hub.experience where id = $1`,
36
- values: [dbWithdrawalRequest.experience_id],
37
- })
38
- .then(exactlyOneRow);
39
- const mpResult = await graphqlClient
40
- .request({
41
- document: START_PENDING_EXPERIENCE_TRANSFER,
42
- variables: {
43
- mpUserId: dbUser.mp_user_id,
44
- mpExperienceId: dbExperience.mp_experience_id,
45
- amount: dbWithdrawalRequest.amount,
46
- currency: dbWithdrawalRequest.currency_key,
47
- metadata: JSON.stringify({
48
- id: `withdrawal_request:${dbWithdrawalRequest.id}`,
49
- }),
50
- },
51
- })
52
- .then((res) => res.transferCurrencyExperienceToUser?.result);
53
- if (!mpResult?.__typename) {
54
- throw new Error(`Failed to start MP transfer: ${mpResult}`);
55
- }
56
- if (mpResult.__typename === "TakeRequestAlreadyTerminal") {
57
- if (mpResult.takeRequest.experienceTransfer) {
58
- const mpTransferId = mpResult.takeRequest.experienceTransfer.id;
59
- await pgClient.query({
60
- text: `
61
- update hub.withdrawal_request
62
- set mp_transfer_id = $2
63
- where id = $1
64
- `,
65
- values: [dbWithdrawalRequest.id, mpTransferId],
66
- });
67
- }
68
- }
69
- if (mpResult?.__typename !== "TransferSuccess" &&
70
- mpResult?.__typename !== "TransferMetadataIdExists") {
71
- throw new Error(`Failed to start MP transfer: ${mpResult}`);
72
- }
73
- const mpTransferId = mpResult.transfer.id;
74
- const mpStatus = mpResult.transfer.status;
75
- await pgClient
76
- .query({
77
- text: `
78
- update hub.withdrawal_request
79
- set mp_transfer_id = $2
80
- where id = $1
81
- `,
82
- values: [dbWithdrawalRequest.id, mpTransferId],
83
- })
84
- .then((res) => {
85
- assert(res.rowCount === 1, `Expected to update a hub.withdrawal_request.mp_transfer_id`);
86
- });
87
- if (mpStatus === TransferStatusKind.Pending ||
88
- mpStatus === TransferStatusKind.Completed) {
89
- }
90
- else {
91
- logger.warn(`Expected status to be PENDING or COMPLETED, but got ${mpStatus}`);
92
- return;
93
- }
94
- await pgClient.query({
95
- text: `
96
- insert into hub.withdrawal(
97
- id,
98
- casino_id,
99
- mp_transfer_id,
100
- user_id,
101
- experience_id,
102
- amount,
103
- currency_key,
104
- status,
105
- withdrawal_request_id
106
- )
107
- values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
108
- `,
109
- values: [
110
- dbWithdrawalRequest.id,
111
- dbWithdrawalRequest.casino_id,
112
- mpTransferId,
113
- dbWithdrawalRequest.user_id,
114
- dbWithdrawalRequest.experience_id,
115
- dbWithdrawalRequest.amount,
116
- dbWithdrawalRequest.currency_key,
117
- mpResult.transfer.status,
118
- dbWithdrawalRequest.id,
119
- ],
120
- });
121
- });
122
- }
123
- export async function processWithdrawalRequests({ casinoId, graphqlClient, pool, }) {
124
- const pendingRequests = await pool.query({
125
- text: `
126
- SELECT wr.*
127
- FROM hub.withdrawal_request wr
128
- WHERE wr.casino_id = $1
129
- AND wr.mp_transfer_id IS NULL
130
- LIMIT 10
131
- `,
132
- values: [casinoId],
133
- });
134
- for (const request of pendingRequests.rows) {
135
- try {
136
- await processWithdrawalRequest({
137
- requestId: request.id,
138
- graphqlClient,
139
- pool,
140
- });
141
- }
142
- catch (error) {
143
- logger.error(error, `Failed to process withdrawal request ${request.id}`);
144
- }
145
- }
146
- }
1
+ export {};
@@ -14,7 +14,6 @@ export type BetLimitPolicyArgs = {
14
14
  bankroll: number;
15
15
  };
16
16
  export type RiskLimits = {
17
- maxWager?: number;
18
17
  maxPayout: number;
19
18
  };
20
19
  export type RiskPolicy = (args: RiskPolicyArgs | BetLimitPolicyArgs) => RiskLimits;
@@ -2,7 +2,6 @@ import { formatCurrency } from "./format-currency.js";
2
2
  import { z } from "zod/v4";
3
3
  const RiskLimitsSchema = z
4
4
  .object({
5
- maxWager: z.number().positive().optional(),
6
5
  maxPayout: z.number().positive(),
7
6
  })
8
7
  .strict();
@@ -21,20 +20,6 @@ export function validateRisk(options) {
21
20
  error: { message, riskLimits: options.riskLimits },
22
21
  };
23
22
  }
24
- if (options.riskLimits.maxWager !== undefined &&
25
- wager > options.riskLimits.maxWager) {
26
- const message = `Wager (${formatCurrency(wager, {
27
- displayUnitName: options.displayUnitName,
28
- displayUnitScale: options.displayUnitScale,
29
- })}) exceeds limit (${formatCurrency(options.riskLimits.maxWager, {
30
- displayUnitName: options.displayUnitName,
31
- displayUnitScale: options.displayUnitScale,
32
- })})`;
33
- return {
34
- ok: false,
35
- error: { message, riskLimits: options.riskLimits },
36
- };
37
- }
38
23
  if (maxPotentialPayout > options.riskLimits.maxPayout) {
39
24
  const message = `Payout (${formatCurrency(maxPotentialPayout, {
40
25
  displayUnitName: options.displayUnitName,
@@ -1,12 +1,15 @@
1
1
  import { ServerOptions } from "../index.js";
2
2
  import { ServerContext } from "../context.js";
3
3
  export type HubServer = {
4
- listen: () => Promise<void>;
4
+ listen: () => Promise<{
5
+ port: number;
6
+ }>;
5
7
  shutdown: () => Promise<void>;
6
8
  };
7
- export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
9
+ export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
8
10
  abortSignal: AbortSignal;
9
11
  context: ServerContext;
10
12
  enableChat: boolean;
11
13
  enablePlayground: boolean;
14
+ port: number;
12
15
  }): HubServer;
@@ -3,7 +3,6 @@ import { grafserv } from "postgraphile/grafserv/express/v4";
3
3
  import postgraphile from "postgraphile";
4
4
  import { createPreset, defaultPlugins } from "./graphile.config.js";
5
5
  import express from "express";
6
- import * as config from "../config.js";
7
6
  import { logger } from "../logger.js";
8
7
  import cors from "./middleware/cors.js";
9
8
  import authentication from "./middleware/authentication.js";
@@ -45,7 +44,7 @@ function createExpressServer(context) {
45
44
  });
46
45
  return app;
47
46
  }
48
- export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }) {
47
+ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }) {
49
48
  const expressServer = createExpressServer(context);
50
49
  const preset = createPreset({
51
50
  plugins: plugins ?? defaultPlugins,
@@ -72,7 +71,11 @@ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, ex
72
71
  return {
73
72
  listen: () => {
74
73
  return new Promise((resolve) => {
75
- nodeServer.listen(config.PORT, resolve);
74
+ nodeServer.listen(port, () => {
75
+ const addr = nodeServer.address();
76
+ const actualPort = typeof addr === "object" && addr ? addr.port : port;
77
+ resolve({ port: actualPort });
78
+ });
76
79
  });
77
80
  },
78
81
  shutdown: () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.18.0-dev.1",
3
+ "version": "1.18.0-dev.3",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "@graphile-contrib/pg-omit-archived": "^4.0.0-beta.4",
53
53
  "@moneypot/hash-herald": "^1.0.0",
54
- "@moneypot/pg-upgrade-schema": "^2.0.4",
54
+ "@moneypot/pg-upgrade-schema": "^2.1.0",
55
55
  "@noble/curves": "^1.5.0",
56
56
  "dotenv": "^16.4.5",
57
57
  "express": "^5.0.1",