feat(rust): slash commands and the next wipe, server half (phase 16)
Five read-only commands registered with api.registerSlashCommands: /status, /wipe, /top, /online and /clan (D126). Every refusal is private, and any answer narrower than public (online names, a clan roster) goes to the caller alone (D127). No command asks a sidecar. The next wipe (D128, D130): six nullable columns on rust_servers, a pure nextWipe(row, now) with the zone arithmetic through Intl, computed on every read. The public server shape gains nextWipe; the admin shape gains the stored schedule; PUT /admin/rust/servers/:id takes the six fields and writes them only when wipeRule is present. server/commands joins ci/bundle.json, which checkBundle caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
const core = require('../../core')
|
||||
const db = require('./servers.db')
|
||||
const { nextWipe } = require('./nextWipe')
|
||||
|
||||
const log = core.logger('servers')
|
||||
|
||||
@@ -136,6 +137,27 @@ function shapePublic(row, state, now) {
|
||||
lastSeenAt: lastSeenAt ? lastSeenAt.toISOString() : null,
|
||||
updatedAt: updatedAt ? updatedAt.toISOString() : null,
|
||||
stale,
|
||||
// Phase 16 (D130): `{ at, source }` or null, computed from the operator's
|
||||
// schedule on every read — never stored, so it cannot go stale after a wipe.
|
||||
// Public: a wipe date is announced to bring players back, not kept secret.
|
||||
nextWipe: nextWipe(row, now),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The schedule as stored, for the admin form: what the operator typed, not what
|
||||
* it computes to. A one-off date that has passed is still returned, and the form
|
||||
* shows it as past (§32.4 reading 5) rather than silently dropping it.
|
||||
*/
|
||||
function scheduleOf(row) {
|
||||
const once = row.wipeOnceAt ? new Date(row.wipeOnceAt) : null
|
||||
return {
|
||||
rule: row.wipeRule || 'none',
|
||||
day: row.wipeDay == null ? null : Number(row.wipeDay),
|
||||
time: row.wipeTime || null,
|
||||
tz: row.wipeTz || null,
|
||||
anchor: row.wipeAnchor || null,
|
||||
onceAt: once && !Number.isNaN(once.getTime()) ? once.toISOString() : null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +206,7 @@ async function listForAdmin(now = Date.now()) {
|
||||
reachable: Boolean(state && state.reachable),
|
||||
bootId: (state && state.bootId) || null,
|
||||
sidecarProtocol: state && state.protocol != null ? Number(state.protocol) : null,
|
||||
schedule: scheduleOf(row),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -204,5 +227,6 @@ module.exports = {
|
||||
getPublic,
|
||||
listForAdmin,
|
||||
shapePublic,
|
||||
scheduleOf,
|
||||
encryptToken,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user