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 +6 -0
- package/package.json +1 -1
- package/src/http/HttpClient.ts +13 -5
- package/src/http/endpoints/user.ts +9 -4
- package/src/index.ts +1 -1
- package/src/types/api.ts +27 -0
- package/src/types/events.ts +3 -0
- package/src/types/game.ts +2 -0
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
package/src/http/HttpClient.ts
CHANGED
|
@@ -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>,
|
|
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<
|
|
34
|
-
overview(interval: number, statName: string): Promise<
|
|
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
|
-
|
|
77
|
-
|
|
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 }
|
package/src/types/events.ts
CHANGED
|
@@ -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. */
|