screeps-connectivity 0.6.0 → 0.8.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 +16 -0
- package/package.json +1 -1
- package/src/http/HttpClient.ts +13 -5
- package/src/http/endpoints/game.ts +8 -4
- package/src/http/endpoints/user.ts +9 -4
- package/src/index.ts +1 -1
- package/src/types/api.ts +83 -0
- package/src/types/events.ts +3 -0
- package/src/types/game.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fb4ab0a: Add a read-only Market section — all orders, my orders, and history — matching the vanilla client.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 620f551: Add Power Creeps pages — list, create, and per-creep power upgrades — from the Overview page.
|
|
12
|
+
|
|
13
|
+
## 0.7.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 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.
|
|
18
|
+
|
|
3
19
|
## 0.6.0
|
|
4
20
|
|
|
5
21
|
### 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
|
|
|
@@ -15,6 +15,10 @@ import type {
|
|
|
15
15
|
ApiGameTickResponse,
|
|
16
16
|
RoomHistoryChunk,
|
|
17
17
|
ApiRoomDecorationsResponse,
|
|
18
|
+
ApiMarketOrdersIndexResponse,
|
|
19
|
+
ApiMarketOrdersResponse,
|
|
20
|
+
ApiMarketMyOrdersResponse,
|
|
21
|
+
ApiMarketStatsResponse,
|
|
18
22
|
} from '../../types/api.js'
|
|
19
23
|
import { createPowerCreepsEndpoints, type PowerCreepsEndpoints } from './power-creeps.js'
|
|
20
24
|
|
|
@@ -49,10 +53,10 @@ export interface GameEndpoints {
|
|
|
49
53
|
removeInvader(id: string): Promise<{ ok: number }>
|
|
50
54
|
powerCreeps: PowerCreepsEndpoints
|
|
51
55
|
market: {
|
|
52
|
-
ordersIndex(shard?: string | null): Promise<
|
|
53
|
-
myOrders(): Promise<
|
|
54
|
-
orders(resourceType: string, shard?: string | null): Promise<
|
|
55
|
-
stats(resourceType: string, shard?: string | null): Promise<
|
|
56
|
+
ordersIndex(shard?: string | null): Promise<ApiMarketOrdersIndexResponse>
|
|
57
|
+
myOrders(): Promise<ApiMarketMyOrdersResponse>
|
|
58
|
+
orders(resourceType: string, shard?: string | null): Promise<ApiMarketOrdersResponse>
|
|
59
|
+
stats(resourceType: string, shard?: string | null): Promise<ApiMarketStatsResponse>
|
|
56
60
|
}
|
|
57
61
|
shards: {
|
|
58
62
|
info(): Promise<ApiShardsInfoResponse>
|
|
@@ -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, ApiUserMoneyHistoryResponse, ApiMarketOrder, ApiMarketOrdersIndexResponse, ApiMarketOrdersResponse, ApiMarketMyOrdersResponse, ApiMarketStat, ApiMarketStatsResponse, ApiPowerCreep, ApiPowerCreepsListResponse } 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 }
|
|
@@ -218,6 +245,8 @@ export interface ApiUserFindResponse {
|
|
|
218
245
|
export interface ApiUserMoneyHistoryResponse {
|
|
219
246
|
ok: number
|
|
220
247
|
page: number
|
|
248
|
+
// True when an older page exists; drives the History "Older" pager.
|
|
249
|
+
hasMore?: boolean
|
|
221
250
|
list: Array<{
|
|
222
251
|
_id: string
|
|
223
252
|
date: string
|
|
@@ -225,10 +254,64 @@ export interface ApiUserMoneyHistoryResponse {
|
|
|
225
254
|
type: string
|
|
226
255
|
balance: number
|
|
227
256
|
change: number
|
|
257
|
+
// Shard the transaction occurred on (official multi-shard servers only).
|
|
258
|
+
shard?: string
|
|
228
259
|
market?: unknown
|
|
229
260
|
}>
|
|
230
261
|
}
|
|
231
262
|
|
|
263
|
+
// Market — a single order from game/market/orders (public) or my-orders (own).
|
|
264
|
+
// `active`/`totalAmount` are returned only for your own orders. `range` is not
|
|
265
|
+
// part of the API response — the client computes it as the room distance to a
|
|
266
|
+
// chosen target room.
|
|
267
|
+
export interface ApiMarketOrder {
|
|
268
|
+
_id: string
|
|
269
|
+
type: 'sell' | 'buy'
|
|
270
|
+
resourceType: string
|
|
271
|
+
price: number
|
|
272
|
+
amount: number
|
|
273
|
+
remainingAmount: number
|
|
274
|
+
/** Original order size — own orders only. */
|
|
275
|
+
totalAmount?: number
|
|
276
|
+
/** Whether the order is currently funded/stocked — own orders only. */
|
|
277
|
+
active?: boolean
|
|
278
|
+
/** Source/target room; absent for token and other roomless orders. */
|
|
279
|
+
roomName?: string
|
|
280
|
+
created?: number
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface ApiMarketOrdersIndexResponse {
|
|
284
|
+
ok: number
|
|
285
|
+
// One entry per resource type that has open orders; `_id` is the resource type.
|
|
286
|
+
list: Array<{ _id: string; count: number }>
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface ApiMarketOrdersResponse {
|
|
290
|
+
ok: number
|
|
291
|
+
list: ApiMarketOrder[]
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Own orders: multi-shard servers return `shards` keyed by shard name;
|
|
295
|
+
// single-shard servers return a flat `list` instead.
|
|
296
|
+
export interface ApiMarketMyOrdersResponse {
|
|
297
|
+
ok: number
|
|
298
|
+
shards?: Record<string, ApiMarketOrder[]>
|
|
299
|
+
list?: ApiMarketOrder[]
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface ApiMarketStat {
|
|
303
|
+
date: string
|
|
304
|
+
transactions: number
|
|
305
|
+
volume: number
|
|
306
|
+
avgPrice: number
|
|
307
|
+
stddevPrice: number
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface ApiMarketStatsResponse {
|
|
311
|
+
ok: number
|
|
312
|
+
stats: ApiMarketStat[]
|
|
313
|
+
}
|
|
314
|
+
|
|
232
315
|
export interface ApiUserMessage {
|
|
233
316
|
_id: string
|
|
234
317
|
date: string
|
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. */
|