Skip to content

About

The main API of Game Node.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Latest commit

 

History

917 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nest Logo

A progressive Node.js framework for building efficient and scalable server-side applications.

NPM Version Package License NPM Downloads CircleCI Coverage Discord Backers on Open Collective Sponsors on Open Collective Support us

Description

A NestJS API responsible for handling all GameNode requests.

Docker

The root docker-compose.yml starts the local dependencies: MySQL, SuperTokens, Redis, MinIO, Manticore, and the Directus blog CMS. The NestJS server runs on the host when you use the development command below. If you are looking to self-host GameNode (server), this is the easiest way to do it.

Important:

Set up the root .env before starting. See Installation and the CMS trial guide for details.

Migrations and Docker

The default docker-compose files do not run migrations automatically. Create and review migrations in development against a disposable database, then commit them with the application changes. Do not generate migrations inside a running production container.

At deployment, the server_migration service in docker-compose.prod.yml runs the committed migrations once and exits; the API starts only after it succeeds, so replicas never run migrations concurrently. Its image tag is independent of the API's. Back up the database before deploying a new migration.

The current Git checkout still needs a versioned initial schema: the historical baseline is ignored by Git. See the fresh installation report for the bootstrap prerequisite and migration workflow.

Use docker-compose.prod.yml as the production definition of the application services, including Directus. Load that file from Git in Coolify. Production MySQL is not in that file: it is a Coolify-managed database resource, shared by GameNode, SuperTokens and Directus with separate databases and users, and backed up by Coolify to R2. Set the production credentials listed in .env.example. API and migration containers reference an immutable lamarcke/game-node-server release tag directly in the production Compose. The production base still needs the deployment corrections listed in the report.

Production requires a one-time manual step: after creating the managed MySQL, run docker/mysql/init-databases.sh inside it to create the SuperTokens and Directus databases/users. See section 6.3 of the fresh installation report. Changing environment variables later does not update existing users.

Development and disposable test services use the same MySQL, Redis and Manticore versions as production. The updated images target fresh installations; existing local volumes need an engine-specific upgrade plan. MinIO is a pinned legacy image for local development; production uploads use external S3/R2 storage.

If you are developing locally, you can use this command to spin up your containers and start the server:

$ yarn start:dev:docker # docker compose up --build -d --wait && yarn start:dev

You can also attach your editor to the Docker container if it supports remote development (like VS Code, IntelliJ IDEA, etc.).

The provided MySQL instance will hold all data for both GameNode Server itself and from Supertokens.

Bugs and issues related to migrations are not covered by support, and should instead be reported to the TypeORM team.

Installation

$ yarn

Use the .env.example file as an example for your own .env file.
All parameters are required.
Some parameters are omitted because they are not needed for local development.

Set CMS_SECRET and CMS_ADMIN_PASSWORD to random values in .env before starting the Docker stack.

The development command starts MySQL, Redis, SuperTokens, MinIO, Manticore, and the CMS locally. Configure managed services only when developing outside that Docker stack.

SuperTokens

Hosting your own instance of Supertokens is not required for local development. You can instead use their public instance url:

SUPERTOKENS_CORE_URI=https://try.supertokens.io

Database

After setting up your database credentials in .env, run the migrations:

$ yarn migration:run

Apply committed migrations on first setup and whenever a release includes pending migrations. An empty database requires the versioned baseline described above.

When developing a schema change, first bring a disposable database to the previous release's schema, edit the entities, then generate and review a new migration:

$ yarn typeorm migration:generate ./src/migrations/DescribeChange -d ./data-source.ts

Test and commit the migration before deployment. Keep applied migrations unchanged and keep synchronize set to false.

Important

ALWAYS check your migrations before running them. Typeorm may sometimes drop important tables and columns.

S3 and ObjectStorage

We store user uploads in a S3 compatible Object Storage service.
For local development, we recommend MinIO, which is already provisioned when you use the default docker-compose.yml file.
For production, you are free to use any service, as long as it's S3 API compatible, like Cloudflare R2, or AWS S3.
The MinIO Browser interface is exposed in port 9001 by default, and the API is exposed at 9000.

Creating a bucket

In the MinIO interface, create a bucket named gamenode-user-uploads. This name is mandatory.
In your bucket settings, visit the 'Anonymous' tab, and add a ruleset to allow anonymous reads in your bucket:
This will make all content in your bucket accessible/downloadable, and is necessary since the API doesn't provide a 'read' endpoint.
If you were upload a file named my_nice_file.png, it would be available at http://localhost:9000/gamenode-user-uploads/my_nice-file.png

Creating MinIO credentials

After starting your MinIO instance, it will be made available at localhost:9001, which you can visit in your browser.
The default username and password is gamenode.
You may create an access token and secret key directly in MinIO interface:

After creating, edit your .env to reflect your new credentials:

S3_ENDPOINT=http://localhost:9000
S3_ACCESS_KEY_ID=RHfLD2qR3MmD2cngzJRE
S3_SECRET_ACCESS_KEY=eRyW1PuHRVRSsqS2RrytugItZNyczDEvTRvhjQJI

IGDB

GameNode's games metadata are powered by IGDB. To use it, you need to set up game-node-sync-igdb. See CONTRIBUTING for a guide.

PSN

The system-wide PSN credential is derived from an NPSSO. PSN_NPSSO_KEY is only the initial value: once an admin sets an NPSSO, the encrypted one stored in the database (using CONNECTION_CREDENTIAL_ENCRYPTION_KEY) takes precedence, and editing the env variable has no effect anymore.

To rotate it without a restart, send PUT /v1/psn/admin/npsso with { "npsso": "..." } as an admin. The value is validated with Sony before being saved, and the response only contains refreshTokenExpiresAt.

An hourly check keeps the credential alive. Authentication failures are logged as errors containing PSN_SYSTEM_AUTH_FAILED, and a warning is logged when the refresh token expires in less than 7 days. Alert on these logs to know when to rotate.

Platform achievements (Feats)

Achievements are rows in achievement_definition, so designers create them without a deploy. Give the designer the editor role in SuperTokens; admin works too. Everything below lives under /v1/achievements/admin.

  • Metrics: GET metrics lists what can be counted (reviews_written, library_games, games_finished, followers, comments_written, awards_participation, manual), the filters each accepts (game, theme and genre ids, or the awards year) and whether it supports a time window. A new metric needs code in src/achievements/metrics/achievement-metrics.ts; a new achievement does not.
  • Definitions: POST definitions creates a draft with a slug (id), a metric, criteria, 1 to 10 tiers (strictly increasing thresholds, 0 to 5000 XP each) and an icon: a kebab-case glyph, an existing game's cover or an existing icon in public/icons. POST definitions/:id/simulate with { "userId" } shows the metric value and reachable tiers without granting anything.
  • Editorial cycle: drafts can be edited (PATCH) and deleted. POST .../publish makes a definition live; after that, the metric, criteria, window and existing tiers are frozen and only new, higher tiers can be appended. POST .../archive stops evaluation and hides it from the catalog, while users keep the tiers they obtained.
  • Events: POST events creates a time window (UTC) with the same cycle. Definitions linked to an event (eventId) count only facts inside its window and are public only once both are published. After publishing, the start is frozen and the end can only be extended.
  • Backfill: publishing a definition, appending a tier or publishing an event grants tiers to users who already qualify, in batches of 500 on the achievements-backfill-queue. Retroactive grants give XP but no notification or feed activity.

Running the app

# development
$ yarn start

# watch mode
$ yarn start:dev

# production mode
$ yarn start:prod

MCP server

The stateless Streamable HTTP endpoint is ${DOMAIN_API}/v1/mcp (locally, http://localhost:5000/v1/mcp). It requires an OAuth access token issued for that resource; website session tokens do not authenticate MCP requests.

Discovery is public at these paths on DOMAIN_API:

  • /.well-known/oauth-protected-resource/v1/mcp
  • /.well-known/oauth-authorization-server/v1/auth
  • /.well-known/oauth-authorization-server (compatibility alias)
Scope Tools
games:read search_games, get_game
library:read get_library_entry, list_collections
library:write add_game_to_library
reviews:write review_game
posts:write create_post
mappings:write list_unmapped_games, map_external_game, dismiss_unmapped_game

The mappings:write tools work through the queue of platform games GameNode could not map. They are only listed and callable for users with the ADMIN role, checked on every request, so holding the scope is not enough. Mappings they write have origin agent, never overwrite an existing mapping, and can be reviewed or reverted with origin = 'agent' in game_external_game. Their writes count toward the same limit.

OAuth also supports openid, profile and offline_access; the last enables rotating refresh tokens. Clients can use CIMD or register dynamically without a preconfigured client id or secret. Writes share a limit of 10 per user per minute and stop immediately when the user is suspended or banned. Reviews require overwrite: true to replace an existing review. Content is plain text, escaped into HTML paragraphs before storage.

Website prerequisite: game-node-clients must provide ${DOMAIN_WEBSITE}/oauth/consent and make ${DOMAIN_WEBSITE}/auth resume the pending authorization after sign-in. The consent page must show the client name, URI, verified CIMD domain and requested scopes, and submit accept/deny through Better Auth's OAuth client. Discovery works before that companion change ships, but users cannot finish connecting. Local end-to-end checks need a stub consent page. Run yarn migration:run before starting the updated API.

For a Claude.ai custom connector, open Customize → Connectors → + → Add custom connector, name it GameNode and enter your publicly reachable HTTPS ${DOMAIN_API}/v1/mcp URL. Leave the OAuth client credentials empty, then connect, sign in and approve the scopes. Claude.ai connects from Anthropic's cloud, so it cannot reach localhost.

For Claude Code, register the local server:

claude mcp add --transport http gamenode http://localhost:5000/v1/mcp

Use the deployed HTTPS URL instead for a remote server. Open /mcp in Claude Code, select GameNode and authenticate to complete sign-in and consent.

To inspect discovery locally:

curl http://localhost:5000/.well-known/oauth-protected-resource/v1/mcp
curl http://localhost:5000/.well-known/oauth-authorization-server/v1/auth

Test

# TypeScript checks for source and tests
$ yarn test:typecheck

# unit tests
$ yarn test

# e2e tests
$ yarn test:e2e

# test coverage
$ yarn test:cov

Jest compiles TypeScript files individually, uses at most two workers, and recycles workers whose heap exceeds 512 MB after a suite. This is not a hard process memory limit, and recycling does not apply to --runInBand. Run yarn test:typecheck for full type checking; CI runs it before Jest. Use yarn test --maxWorkers=N to override the worker limit.

Keep in mind that it's not possible to test Supertokens' routes (nor should we have to).

Support

Feel free to reach out to us through a Github Issue. We can help you set up your own instance of GameNode, or help you with any other issue you might have.

PS: If you have issues with overral app usage, please fill an issue in the corresponding repository.
For example, if you have issues with the GameNode website, fill an issue in the game-node-web repository.

About

The main API of Game Node.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages