screeps-connectivity 0.6.0 → 0.7.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 69d132d: Add an account Overview page (GCL/GPL rings, lifetime stats, per-room minimap previews) and a public Profile page with routing between them; optional dashboard endpoints (`user/overview`, `user/rooms`) now fail silently on servers that don't implement them.
8
+
3
9
  ## 0.6.0
4
10
 
5
11
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screeps-connectivity",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "repository": {
@@ -16,6 +16,14 @@ export interface RateLimitInfo {
16
16
  reset: number
17
17
  }
18
18
 
19
+ export interface RequestOptions {
20
+ /** Internal: marks the post-auth retry so a second 401 doesn't loop. */
21
+ isRetry?: boolean
22
+ /** Suppress user-facing surfacing of failures (the http:error event carries the
23
+ * flag through). Use for optional endpoints the caller handles gracefully. */
24
+ silent?: boolean
25
+ }
26
+
19
27
  export class HttpClient extends EventTarget {
20
28
  readonly baseUrl: string
21
29
  private readonly authStrategy: AuthStrategy
@@ -79,7 +87,7 @@ export class HttpClient extends EventTarget {
79
87
  this.token = token
80
88
  }
81
89
 
82
- async request<T>(method: string, path: string, body?: Record<string, unknown>, isRetry = false): Promise<T> {
90
+ async request<T>(method: string, path: string, body?: Record<string, unknown>, opts: RequestOptions = {}): Promise<T> {
83
91
  this.logger.log(method, path)
84
92
  const url = new URL(path.startsWith('/') ? path.slice(1) : path, this.baseUrl)
85
93
  const headers: Record<string, string> = {}
@@ -115,9 +123,9 @@ export class HttpClient extends EventTarget {
115
123
 
116
124
  this.updateRateLimit(path, res)
117
125
 
118
- if (res.status === 401 && !isRetry && !this.authenticating) {
126
+ if (res.status === 401 && !opts.isRetry && !this.authenticating) {
119
127
  await this.authenticate()
120
- return this.request<T>(method, path, body, true)
128
+ return this.request<T>(method, path, body, { ...opts, isRetry: true })
121
129
  }
122
130
 
123
131
  // 304: some servers (e.g. private Screeps) send a body with 304 — treat it as success
@@ -125,7 +133,7 @@ export class HttpClient extends EventTarget {
125
133
  let body = ''
126
134
  try { body = await res.text() } catch { /* ignore */ }
127
135
  const error = new Error(`HTTP ${res.status}: ${body}`)
128
- this.emit('http:error', { method, path, status: res.status, error })
136
+ this.emit('http:error', { method, path, status: res.status, error, silent: opts.silent })
129
137
  throw error
130
138
  }
131
139
 
@@ -135,7 +143,7 @@ export class HttpClient extends EventTarget {
135
143
 
136
144
  if (typeof data['error'] === 'string') {
137
145
  const error = new Error(`Screeps API error: ${data['error']}`)
138
- this.emit('http:error', { method, path, status: res.status, error })
146
+ this.emit('http:error', { method, path, status: res.status, error, silent: opts.silent })
139
147
  throw error
140
148
  }
141
149
 
@@ -3,6 +3,8 @@ import type {
3
3
  ApiUserBranchesResponse,
4
4
  ApiUserFindResponse,
5
5
  ApiUserMoneyHistoryResponse,
6
+ ApiUserOverviewResponse,
7
+ ApiUserRoomsResponse,
6
8
  } from '../../types/api.js'
7
9
  import { createUserMessagesEndpoints, type UserMessagesEndpoints } from './user-messages.js'
8
10
 
@@ -30,8 +32,8 @@ export interface UserEndpoints {
30
32
  }
31
33
  console(expression: string, shard?: string | null): Promise<unknown>
32
34
  stats(interval: number): Promise<unknown>
33
- rooms(id: string): Promise<unknown>
34
- overview(interval: number, statName: string): Promise<unknown>
35
+ rooms(id: string): Promise<ApiUserRoomsResponse>
36
+ overview(interval: number, statName: string): Promise<ApiUserOverviewResponse>
35
37
  worldStatus(): Promise<{ ok: number; status: 'normal' | 'lost' | 'empty' }>
36
38
  worldStartRoom(shard?: string | null): Promise<unknown>
37
39
  find(query: { username: string } | { id: string }): Promise<ApiUserFindResponse>
@@ -73,8 +75,11 @@ export function createUserEndpoints(http: HttpClient): UserEndpoints {
73
75
  },
74
76
  console: (expression, shard) => http.request('POST', '/api/user/console', withShard({ expression }, shard)),
75
77
  stats: (interval) => http.request('GET', '/api/user/stats', { interval }),
76
- rooms: (id) => http.request('GET', '/api/user/rooms', { id }),
77
- overview: (interval, statName) => http.request('GET', '/api/user/overview', { interval, statName }),
78
+ // Best-effort dashboard data: not every server implements these, and the
79
+ // Overview page degrades gracefully (zeros / no tiles), so a failure here
80
+ // shouldn't raise a user-facing error toast — mark them silent.
81
+ rooms: (id) => http.request('GET', '/api/user/rooms', { id }, { silent: true }),
82
+ overview: (interval, statName) => http.request('GET', '/api/user/overview', { interval, statName }, { silent: true }),
78
83
  worldStatus: () => http.request('GET', '/api/user/world-status'),
79
84
  worldStartRoom: (shard) => http.request('GET', '/api/user/world-start-room', withShard({}, shard)),
80
85
  find: (query) => http.request('GET', '/api/user/find', query as Record<string, unknown>),
package/src/index.ts CHANGED
@@ -40,7 +40,7 @@ export type {
40
40
 
41
41
  export { fetchServerVersion, fetchAuthModInfo, checkUsername, checkEmail, registerUser, getServerFeature, getScreepsmodAuth } from './http/fetchServerVersion.js'
42
42
  export type { ApiAuthModInfoResponse } from './http/fetchServerVersion.js'
43
- export type { RoomHistoryChunk, ApiRoomDecorationsResponse, ApiRoomDecorationItem, ApiRoomDecorationDef, ApiRoomDecorationGraphic, ApiRoomDecorationActive } from './types/api.js'
43
+ export type { RoomHistoryChunk, ApiRoomDecorationsResponse, ApiRoomDecorationItem, ApiRoomDecorationDef, ApiRoomDecorationGraphic, ApiRoomDecorationActive, ApiUserOverviewResponse, ApiUserOverviewTotals, ApiUserRoomsResponse } from './types/api.js'
44
44
  export { ROOM_DECORATIONS_MOCK } from './mocks/roomDecorations.js'
45
45
 
46
46
  export { badgeToSvg } from './badge/index.js'
package/src/types/api.ts CHANGED
@@ -21,11 +21,38 @@ export interface ApiAuthMeResponse {
21
21
  username: string
22
22
  cpu: number
23
23
  gcl: number
24
+ /** Raw accumulated power points; Global Power Level derives from this. Absent on servers without the power system. */
25
+ power?: number
24
26
  credits: number
25
27
  badge: import('./game.js').Badge
26
28
  password: boolean
27
29
  }
28
30
 
31
+ /** Per-stat lifetime totals over the requested interval — the values behind the Overview stat tiles. Individual fields may be absent on servers that don't track that stat. */
32
+ export interface ApiUserOverviewTotals {
33
+ energyControl?: number
34
+ energyHarvested?: number
35
+ energyConstruction?: number
36
+ energyCreeps?: number
37
+ creepsProduced?: number
38
+ creepsLost?: number
39
+ powerProcessed?: number
40
+ }
41
+
42
+ /** Response of GET /api/user/overview. Only `totals` is consumed by the Overview tiles; per-room time series (shards/stats) are omitted until the room band is built. */
43
+ export interface ApiUserOverviewResponse {
44
+ ok: number
45
+ totals?: ApiUserOverviewTotals
46
+ statsMax?: number
47
+ }
48
+
49
+ /** Response of GET /api/user/rooms?id=<userId> — the rooms a user owns. Multishard servers key by shard; single-shard servers may return a flat list. */
50
+ export interface ApiUserRoomsResponse {
51
+ ok: number
52
+ shards?: Record<string, string[]>
53
+ rooms?: string[]
54
+ }
55
+
29
56
  export interface ApiAuthQueryTokenResponse {
30
57
  ok: number
31
58
  token: { full: boolean }
@@ -68,6 +68,9 @@ export interface HttpClientEvents {
68
68
  path: string
69
69
  status: number
70
70
  error: Error
71
+ // Set when the request opted out of user-facing error surfacing (e.g. an
72
+ // optional endpoint whose failure the caller handles gracefully).
73
+ silent?: boolean
71
74
  }
72
75
  'http:tokenRefresh': {
73
76
  token: string
package/src/types/game.ts CHANGED
@@ -66,6 +66,8 @@ export interface UserInfo {
66
66
  email: string
67
67
  cpu: number
68
68
  gcl: number
69
+ /** Raw accumulated power points; Global Power Level derives from this. Absent on servers without the power system. */
70
+ power?: number
69
71
  credits: number
70
72
  badge: Badge
71
73
  /** True when the account has a password set. Absent for password-less accounts (e.g. Steam-only logins). Only present for the authenticated user's own info. */