@moneypot/hub 1.19.4 → 1.19.6

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.
@@ -26,7 +26,7 @@ export function pickRandomOutcome({ outcomes, finalHash, }, floatEpsilon = 1e-10
26
26
  for (let i = 0; i < outcomesWithProbability.length; i++) {
27
27
  const outcome = outcomesWithProbability[i];
28
28
  cumulativeProb += outcome.probability;
29
- if (roll <= cumulativeProb) {
29
+ if (roll < cumulativeProb) {
30
30
  return { outcomeIdx: i, roll };
31
31
  }
32
32
  }
@@ -1,6 +1,6 @@
1
- import { Express } from "express";
1
+ import { type ConfigureAppArgs } from "./server/index.js";
2
2
  import { type PluginIdentity } from "./server/graphile.config.js";
3
- import { ServerContext } from "./context.js";
3
+ import { type ServerContext } from "./context.js";
4
4
  declare global {
5
5
  namespace Grafast {
6
6
  interface Context {
@@ -22,10 +22,9 @@ export { type CustomGameConfig, type CustomGameConfigMap, } from "./custom-game-
22
22
  export { validateRisk, type RiskPolicy, type RiskPolicyArgs, type RiskLimits, } from "./risk-policy.js";
23
23
  export type PluginContext = Grafast.Context;
24
24
  export { defaultPlugins, type PluginIdentity, type UserSessionContext, type HubPlugin, } from "./server/graphile.config.js";
25
- export type ConfigureAppArgs = {
26
- app: Express;
27
- superuserPool: ServerContext["superuserPool"];
28
- };
25
+ export type { ConfigureAppArgs } from "./server/index.js";
26
+ import { runMigrations } from "./migrations.js";
27
+ export { runMigrations };
29
28
  import type { HubPlugin } from "./server/graphile.config.js";
30
29
  export type ServerOptions = {
31
30
  configureApp?: (args: ConfigureAppArgs) => void;
@@ -37,9 +36,6 @@ export type ServerOptions = {
37
36
  enablePlayground?: boolean;
38
37
  port?: number;
39
38
  };
40
- export declare function runMigrations(options: {
41
- userDatabaseMigrationsPath?: string;
42
- }): Promise<void>;
43
39
  export declare function startAndListen(options: ServerOptions): Promise<{
44
40
  port: number;
45
41
  stop: () => Promise<void>;
package/dist/src/index.js CHANGED
@@ -1,77 +1,12 @@
1
- import PgUpgradeSchema, { DatabaseAheadError, } from "@moneypot/pg-upgrade-schema";
2
- import * as db from "./db/index.js";
3
1
  import * as config from "./config.js";
4
- import { createHubServer } from "./server/index.js";
5
- import { initializeTransferProcessors } from "./process-transfers/index.js";
6
- import { join } from "path";
7
2
  import { logger } from "./logger.js";
8
- import { createServerContext, closeServerContext, } from "./context.js";
3
+ import { createHubServer } from "./server/index.js";
9
4
  export { HubGameConfigPlugin, } from "./plugins/hub-game-config-plugin.js";
10
5
  export { validateRisk, } from "./risk-policy.js";
11
6
  export { defaultPlugins, } from "./server/graphile.config.js";
12
- export async function runMigrations(options) {
13
- if (options.userDatabaseMigrationsPath) {
14
- const { existsSync, statSync } = await import("fs");
15
- if (!existsSync(options.userDatabaseMigrationsPath)) {
16
- throw new Error(`userDatabaseMigrationsPath does not exist: ${options.userDatabaseMigrationsPath}`);
17
- }
18
- const stats = statSync(options.userDatabaseMigrationsPath);
19
- if (!stats.isDirectory()) {
20
- throw new Error(`userDatabaseMigrationsPath is not a directory: ${options.userDatabaseMigrationsPath}`);
21
- }
22
- }
23
- const pgClient = db.getPgClient(config.SUPERUSER_DATABASE_URL);
24
- await pgClient.connect();
25
- try {
26
- try {
27
- await PgUpgradeSchema.default({
28
- pgClient,
29
- dirname: join(import.meta.dirname, "pg-versions"),
30
- schemaName: "hub_core_versions",
31
- silent: process.env.NODE_ENV === "test",
32
- });
33
- }
34
- catch (e) {
35
- logger.error(e, "Error upgrading core schema");
36
- if (e instanceof DatabaseAheadError) {
37
- logger.error(`${"⚠️".repeat(10)}\n@moneypot/hub database was reset to prepare for a production release and you must reset your database to continue. Please see <https://www.npmjs.com/package/@moneypot/hub#change-log> for more info.`);
38
- process.exit(1);
39
- }
40
- throw e;
41
- }
42
- if (options.userDatabaseMigrationsPath) {
43
- await PgUpgradeSchema.default({
44
- pgClient,
45
- dirname: options.userDatabaseMigrationsPath,
46
- schemaName: "hub_user_versions",
47
- silent: process.env.NODE_ENV === "test",
48
- });
49
- }
50
- }
51
- finally {
52
- await pgClient.end();
53
- }
54
- }
55
- async function initialize(options) {
56
- if (options.signal.aborted) {
57
- logger.info("Initialization aborted by graceful shutdown");
58
- return;
59
- }
60
- await runMigrations({
61
- userDatabaseMigrationsPath: options.userDatabaseMigrationsPath,
62
- });
63
- if (options.signal.aborted) {
64
- logger.info("Initialization aborted by graceful shutdown");
65
- return;
66
- }
67
- if (process.env.NODE_ENV !== "test") {
68
- initializeTransferProcessors({
69
- signal: options.signal,
70
- pool: options.context.superuserPool,
71
- });
72
- }
73
- }
74
- export async function startAndListen(options) {
7
+ import { runMigrations } from "./migrations.js";
8
+ export { runMigrations };
9
+ function validateOptions(options) {
75
10
  if (options.plugins && options.plugins.some((p) => typeof p === "function")) {
76
11
  throw new Error("`plugins` should be an array of HubPlugin but one of the items is a function. Did you forget to call it?");
77
12
  }
@@ -83,60 +18,38 @@ export async function startAndListen(options) {
83
18
  !options.exportSchemaSDLPath.startsWith("/")) {
84
19
  throw new Error(`exportSchemaSDLPath must be an absolute path, got ${options.exportSchemaSDLPath}`);
85
20
  }
86
- const abortController = new AbortController();
87
- let isShuttingDown = false;
88
- const context = createServerContext();
89
- await initialize({
21
+ }
22
+ export async function startAndListen(options) {
23
+ validateOptions(options);
24
+ await runMigrations({
90
25
  userDatabaseMigrationsPath: options.userDatabaseMigrationsPath,
91
- signal: abortController.signal,
92
- context,
93
26
  });
94
27
  const hubServer = createHubServer({
95
28
  configureApp: options.configureApp,
96
29
  plugins: options.plugins,
97
30
  exportSchemaSDLPath: options.exportSchemaSDLPath,
98
31
  extraPgSchemas: options.extraPgSchemas,
99
- abortSignal: abortController.signal,
100
- context,
101
32
  enableChat: options.enableChat ?? true,
102
33
  enablePlayground: options.enablePlayground ?? true,
103
34
  port: options.port ?? config.PORT,
35
+ runProcessors: process.env.NODE_ENV !== "test",
104
36
  });
105
- const gracefulShutdown = async ({ exit = true } = {}) => {
106
- if (isShuttingDown) {
107
- logger.warn("Already shutting down.");
108
- return;
109
- }
110
- isShuttingDown = true;
111
- logger.info("Shutting down gracefully...");
112
- abortController.abort();
113
- await new Promise((resolve) => setTimeout(resolve, 500));
114
- logger.info("Closing resources...");
115
- await hubServer.shutdown();
116
- try {
117
- await Promise.race([
118
- closeServerContext(context),
119
- new Promise((_, reject) => setTimeout(() => reject(new Error("Database cleanup timeout")), 3000)),
120
- ]);
121
- logger.info("Cleanup complete.");
122
- }
123
- catch (err) {
124
- logger.warn(err, "Cleanup error (proceeding anyway)");
125
- }
126
- if (exit) {
127
- process.exit(0);
128
- }
129
- };
130
37
  if (process.env.NODE_ENV !== "test") {
131
- process.on("SIGINT", gracefulShutdown);
132
- process.on("SIGTERM", gracefulShutdown);
133
- }
134
- return hubServer.listen().then(({ port }) => {
135
- return {
136
- port,
137
- stop: async () => {
138
- await gracefulShutdown({ exit: false });
139
- },
38
+ const handler = () => {
39
+ hubServer
40
+ .shutdown()
41
+ .then(() => process.exit(0))
42
+ .catch((err) => {
43
+ logger.error(err, "Shutdown error");
44
+ process.exit(1);
45
+ });
140
46
  };
141
- });
47
+ process.on("SIGINT", handler);
48
+ process.on("SIGTERM", handler);
49
+ }
50
+ const { port } = await hubServer.listen();
51
+ return {
52
+ port,
53
+ stop: () => hubServer.shutdown(),
54
+ };
142
55
  }
@@ -0,0 +1,3 @@
1
+ export declare function runMigrations(options: {
2
+ userDatabaseMigrationsPath?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import PgUpgradeSchema, { DatabaseAheadError, } from "@moneypot/pg-upgrade-schema";
2
+ import * as db from "./db/index.js";
3
+ import * as config from "./config.js";
4
+ import { join } from "path";
5
+ import { logger } from "./logger.js";
6
+ export async function runMigrations(options) {
7
+ if (options.userDatabaseMigrationsPath) {
8
+ const { existsSync, statSync } = await import("fs");
9
+ if (!existsSync(options.userDatabaseMigrationsPath)) {
10
+ throw new Error(`userDatabaseMigrationsPath does not exist: ${options.userDatabaseMigrationsPath}`);
11
+ }
12
+ const stats = statSync(options.userDatabaseMigrationsPath);
13
+ if (!stats.isDirectory()) {
14
+ throw new Error(`userDatabaseMigrationsPath is not a directory: ${options.userDatabaseMigrationsPath}`);
15
+ }
16
+ }
17
+ const pgClient = db.getPgClient(config.SUPERUSER_DATABASE_URL);
18
+ await pgClient.connect();
19
+ try {
20
+ try {
21
+ await PgUpgradeSchema.default({
22
+ pgClient,
23
+ dirname: join(import.meta.dirname, "pg-versions"),
24
+ schemaName: "hub_core_versions",
25
+ silent: process.env.NODE_ENV === "test",
26
+ });
27
+ }
28
+ catch (e) {
29
+ logger.error(e, "Error upgrading core schema");
30
+ if (e instanceof DatabaseAheadError) {
31
+ logger.error(`${"⚠️".repeat(10)}\n@moneypot/hub database was reset to prepare for a production release and you must reset your database to continue. Please see <https://www.npmjs.com/package/@moneypot/hub#change-log> for more info.`);
32
+ process.exit(1);
33
+ }
34
+ throw e;
35
+ }
36
+ if (options.userDatabaseMigrationsPath) {
37
+ await PgUpgradeSchema.default({
38
+ pgClient,
39
+ dirname: options.userDatabaseMigrationsPath,
40
+ schemaName: "hub_user_versions",
41
+ silent: process.env.NODE_ENV === "test",
42
+ });
43
+ }
44
+ }
45
+ finally {
46
+ await pgClient.end();
47
+ }
48
+ }
@@ -1,4 +1,3 @@
1
- import { ServerOptions } from "../index.js";
2
1
  import { ServerContext } from "../context.js";
3
2
  export type HubServer = {
4
3
  listen: () => Promise<{
@@ -6,10 +5,20 @@ export type HubServer = {
6
5
  }>;
7
6
  shutdown: () => Promise<void>;
8
7
  };
9
- export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
10
- abortSignal: AbortSignal;
11
- context: ServerContext;
8
+ import type { Express } from "express";
9
+ import type { HubPlugin } from "./graphile.config.js";
10
+ export type ConfigureAppArgs = {
11
+ app: Express;
12
+ superuserPool: ServerContext["superuserPool"];
13
+ };
14
+ export type CreateHubServerOptions = {
15
+ configureApp?: (args: ConfigureAppArgs) => void;
16
+ plugins?: readonly HubPlugin[];
17
+ extraPgSchemas?: string[];
18
+ exportSchemaSDLPath?: string;
12
19
  enableChat: boolean;
13
20
  enablePlayground: boolean;
14
21
  port: number;
15
- }): HubServer;
22
+ runProcessors: boolean;
23
+ };
24
+ export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, enableChat, enablePlayground, port, runProcessors, }: CreateHubServerOptions): HubServer;
@@ -2,6 +2,8 @@ import { createServer as createNodeServer } from "node:http";
2
2
  import { grafserv } from "postgraphile/grafserv/express/v4";
3
3
  import postgraphile from "postgraphile";
4
4
  import { createPreset, defaultPlugins } from "./graphile.config.js";
5
+ import { createServerContext, closeServerContext, } from "../context.js";
6
+ import { initializeTransferProcessors } from "../process-transfers/index.js";
5
7
  import express from "express";
6
8
  import { logger } from "../logger.js";
7
9
  import cors from "./middleware/cors.js";
@@ -44,13 +46,15 @@ function createExpressServer(context) {
44
46
  });
45
47
  return app;
46
48
  }
47
- export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, port, }) {
49
+ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, enableChat, enablePlayground, port, runProcessors, }) {
50
+ const abortController = new AbortController();
51
+ const context = createServerContext();
48
52
  const expressServer = createExpressServer(context);
49
53
  const { preset, pgService } = createPreset({
50
54
  plugins: plugins ?? defaultPlugins,
51
55
  exportSchemaSDLPath,
52
56
  extraPgSchemas: extraPgSchemas ?? [],
53
- abortSignal,
57
+ abortSignal: abortController.signal,
54
58
  context,
55
59
  enableChat,
56
60
  enablePlayground,
@@ -64,10 +68,16 @@ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, ex
64
68
  nodeServer.on("error", (e) => {
65
69
  logger.error(e);
66
70
  });
67
- const mountMiddlewarePromise = serv.addTo(expressServer, nodeServer);
71
+ let isShuttingDown = false;
68
72
  return {
69
73
  listen: async () => {
70
- await mountMiddlewarePromise;
74
+ if (runProcessors) {
75
+ initializeTransferProcessors({
76
+ signal: abortController.signal,
77
+ pool: context.superuserPool,
78
+ });
79
+ }
80
+ await serv.addTo(expressServer, nodeServer);
71
81
  await pgl.getSchema();
72
82
  return new Promise((resolve) => {
73
83
  nodeServer.listen(port, () => {
@@ -78,12 +88,23 @@ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, ex
78
88
  });
79
89
  },
80
90
  shutdown: async () => {
91
+ if (isShuttingDown) {
92
+ logger.warn("Already shutting down.");
93
+ return;
94
+ }
95
+ isShuttingDown = true;
96
+ logger.info("Shutting down gracefully...");
97
+ abortController.abort();
98
+ await new Promise((resolve) => setTimeout(resolve, 500));
99
+ logger.info("Closing resources...");
81
100
  nodeServer.closeAllConnections();
101
+ await closeServerContext(context);
82
102
  await pgService.release?.();
83
103
  await pgl.release();
84
104
  await new Promise((resolve) => {
85
105
  nodeServer.close(() => resolve());
86
106
  });
107
+ logger.info("Cleanup complete.");
87
108
  },
88
109
  };
89
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.19.4",
3
+ "version": "1.19.6",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [