Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
patreon: ags131
github: [ags131]
github: [AlinaNova21]
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) Adam Shumann 2017
Copyright (c) Alina Shumann 2026

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ config.yml example: (This can be the same file as screeps-launcher's config.yml)
# Values set here will override any saved via CLI on server startup
serverConfig:
map: random_1x2 # utils.importMap will be called automatically with this value, see utils.importMap above
mapFile: /path/to/map.json # Alternative to map: import from a local JSON file
tickRate: 200
socketUpdateRate: 200
whitelist: # Does not restrict login, only restricts spawning
Expand All @@ -110,10 +111,29 @@ serverConfig:
<h1>Welcome</h1>
<div>Powered by screepsmod-admin-utils</div>
statsToken: ...splusToken... # This enables submitting stats to S+ Grafana. Note: shardName MUST be set
market: # Config block passed to your market mod — see that mod's documentation for structure
features: # Custom features to expose to clients
- name: customFeature
version: 1
gclToCPU: true
maxCPU: 100
baseCPU: 20
stepCPU: 10
morgan: dev # HTTP request logging format: dev, combined, tiny, short, common. Absent or false = disabled
cors:
origins: # List of allowed origins; absent or empty disables CORS entirely
- https://example.com
- http://localhost:8080
allowedHeaders: # Optional — these are the defaults
- Authorization
- Content-Type
- X-Token
- X-Username
- X-Server-Password
exposedHeaders: # Optional — these are the defaults
- X-Token
- X-Username
- X-Server-Password
```

## Endpoints
Expand Down
4 changes: 1 addition & 3 deletions lib/backend.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
const authroute = require('@screeps/backend/lib/game/api/auth')
const util = require('util')
const fs = require('fs')
const R = require('ramda')

const readFile = util.promisify(fs.readFile)

const indexById = R.indexBy(R.prop('_id'))
const indexById = arr => Object.fromEntries(arr.map(o => [o._id, o]))

module.exports = (config) => {
config.backend.features = config.backend.features || []
Expand Down
4 changes: 2 additions & 2 deletions lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ module.exports = (config) => {
}
},
async banUser (username, remove = false) {
const user = await db.users.findOne({ username: username })
const user = await db.users.findOne({ username })
if (!user) {
return `Can't find user "${username}"`
}
Expand All @@ -173,7 +173,7 @@ module.exports = (config) => {
}
},
async unbanUser (username) {
const user = await db.users.findOne({ username: username })
const user = await db.users.findOne({ username })
if (!user) {
return `Can't find user "${username}"`
} else if (user.active !== 0) {
Expand Down
3 changes: 3 additions & 0 deletions lib/mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[tools]
node = "24"
pnpm = "10"
43 changes: 43 additions & 0 deletions lib/services/cors/backend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* config.yml
cors:
origins: string[] # list of allowed origins; absent/empty = CORS disabled
allowedHeaders: string[] # optional override
exposedHeaders: string[] # optional override
*/

const cors = require('cors')

const DEFAULT_ALLOWED_HEADERS = ['Authorization', 'Content-Type', 'X-Token', 'X-Username', 'X-Server-Password']
const DEFAULT_EXPOSED_HEADERS = ['X-Token', 'X-Username', 'X-Server-Password']
const ALLOWED_METHODS = 'GET,HEAD,PUT,PATCH,POST,DELETE'

module.exports = function (config) {
config.cors = {
origins: [],
allowedHeaders: DEFAULT_ALLOWED_HEADERS.slice(),
exposedHeaders: DEFAULT_EXPOSED_HEADERS.slice()
}

config.utils.on('config:update:cors', function (v) {
if (!v || typeof v !== 'object') return
config.cors.origins = Array.isArray(v.origins) ? v.origins : []
config.cors.allowedHeaders = v.allowedHeaders || DEFAULT_ALLOWED_HEADERS.slice()
config.cors.exposedHeaders = v.exposedHeaders || DEFAULT_EXPOSED_HEADERS.slice()
})

const corsMiddleware = cors(function (req, cb) {
const { origins, allowedHeaders, exposedHeaders } = config.cors
if (!origins || !origins.length) return cb(null, { origin: false })
cb(null, {
origin: origins,
methods: ALLOWED_METHODS,
allowedHeaders,
exposedHeaders,
preflightContinue: false
})
})

config.backend.on('expressPreConfig', function (app) {
app.use(corsMiddleware)
})
}
7 changes: 3 additions & 4 deletions lib/services/importMap/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const path = require('path')
const axios = require('axios')
const fs = require('fs').promises

const log = (...args) => console.log('[ImportMap]', ...args)
Expand Down Expand Up @@ -140,7 +139,7 @@ const getMapFromUrl = async (urlOrMapId) => {
if (urlOrMapId.startsWith('random')) {
const [, size] = urlOrMapId.split('_')
const [width, height] = size.split('x').map(v => +v || 1)
const { data } = await axios.get('https://maps.screepspl.us/maps/index.json')
const data = await fetch('https://maps.screepspl.us/maps/index.json').then(r => r.json())

const maps = Object.values(data).filter(m => +m.width === width && +m.height === height)
if (!maps.length) {
Expand All @@ -154,7 +153,7 @@ const getMapFromUrl = async (urlOrMapId) => {
if (url !== urlOrMapId) {
log(`Importing map from: ${url}`)
}
const { data: { rooms } } = await axios.get(url)
const { rooms } = await fetch(url).then(r => r.json())
return rooms
}

Expand Down Expand Up @@ -191,7 +190,7 @@ const exportMap = async (config) => {
const room = {
room: roomName,
terrain: terrain.terrain,
objects: objects
objects
}
Object.assign(room, roomData)
count++
Expand Down
21 changes: 21 additions & 0 deletions lib/services/morgan/backend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* config.yml
morgan: dev # any morgan format string; absent or false = disabled
*/

const morgan = require('morgan')

const noop = (req, res, next) => next()

module.exports = function (config) {
let morganMiddleware = noop

config.utils.on('config:update:morgan', function (v) {
morganMiddleware = v ? morgan(v) : noop
})

config.backend.on('expressPreConfig', function (app) {
app.use(function (req, res, next) {
morganMiddleware(req, res, next)
})
})
}
17 changes: 5 additions & 12 deletions lib/services/stats/cronjobs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const axios = require('axios')

module.exports = config => {
config.cronjobs.stats = [15, async () => {
const { env } = config.common.storage
Expand All @@ -15,18 +13,13 @@ module.exports = config => {
}, {})
}
delete stats.ticks.ticks
axios({
fetch('https://screepspl.us/api/stats/submit', {
method: 'POST',
url: 'https://screepspl.us/api/stats/submit',
auth: {
username: 'token',
password: config.utils.statsToken
headers: {
Authorization: 'Basic ' + Buffer.from(`token:${config.utils.statsToken}`).toString('base64'),
'Content-Type': 'application/json'
},
data: {
servers: {
[shard]: stats
}
}
body: JSON.stringify({ servers: { [shard]: stats } })
})
} catch (e) {
console.error(e)
Expand Down
7 changes: 4 additions & 3 deletions lib/services/warpath/wrapper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const _ = require('lodash')

// const ACTIVE_THRESHOLD = 0.5 * (60)
// const DELETE_THRESHOLD = 5 * (60)

Expand All @@ -15,7 +13,10 @@ function init (conf) {

const api = {
async roomobjects (room, shard) {
return _.groupBy(await db['rooms.objects'].find({ room }), 'type')
return (await db['rooms.objects'].find({ room })).reduce((acc, o) => {
;(acc[o.type] = acc[o.type] || []).push(o)
return acc
}, {})
},
async time (shard) {
const gameTime = await env.get('gameTime')
Expand Down
12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
{
"name": "screepsmod-admin-utils",
"version": "1.35.1",
"description": "",
"description": "Admin utilities and services for Screeps Private Server",
"repository": {
"url": "https://github.com/ScreepsMods/screepsmod-admin-utils"
},
"main": "index.js",
"scripts": {
"test": "standard",
"2npm": "publish"
"test": "standard"
},
"devDependencies": {
"@screeps/backend": "^3.2.6",
Expand All @@ -23,10 +22,9 @@
"author": "Alina Shumann",
"license": "MIT",
"dependencies": {
"axios": "^0.19.0",
"body-parser": "^1.19.0",
"lodash": "^4.17.21",
"ramda": "^0.30.1",
"body-parser": "^2.2.2",
"cors": "^2.8.5",
"morgan": "^1.10.0",
"screepsmod-admin-utils-ui": "^0.4.0",
"yamljs": "^0.3.0"
},
Expand Down
Loading
Loading