dredless 0.4.0 → 0.5.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/dist/browser/dredless.global.js +58 -1
- package/dist/browser/dredless.global.js.map +3 -3
- package/docs/API_REFERENCE.md +1 -4
- package/docs/BROWSER_API.md +2 -0
- package/docs/NODE_API.md +16 -1
- package/package.json +1 -1
- package/src/browser.d.ts +3 -1
- package/src/browser.js +4 -2
- package/src/index.d.ts +12 -4
- package/src/index.js +3 -1
- package/src/network/index.js +1 -1
- package/src/network/servers.d.ts +2 -0
- package/src/network/servers.js +59 -2
package/docs/API_REFERENCE.md
CHANGED
|
@@ -60,16 +60,13 @@ Both runtime entrypoints re-export world/model classes, protocol builders, confi
|
|
|
60
60
|
|
|
61
61
|
### `Server`
|
|
62
62
|
|
|
63
|
-
Returned by `fetchServers()`.
|
|
63
|
+
Returned by `fetchServers()`. Player counts and ping are returned separately by `fetchServerStatus()` or `fetchServerStatuses()`.
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
66
|
interface Server {
|
|
67
67
|
index: number;
|
|
68
68
|
domain: string;
|
|
69
69
|
description: string;
|
|
70
|
-
playerCount: number;
|
|
71
|
-
maxPlayerCount: number;
|
|
72
|
-
ping: number | null;
|
|
73
70
|
}
|
|
74
71
|
```
|
|
75
72
|
|
package/docs/BROWSER_API.md
CHANGED
|
@@ -41,6 +41,8 @@ interface DredlessBrowserNamespace {
|
|
|
41
41
|
fetchNoticeVersion: typeof fetchNoticeVersion;
|
|
42
42
|
fetchGameVersion: typeof fetchGameVersion;
|
|
43
43
|
fetchServers: typeof fetchServers;
|
|
44
|
+
fetchServerStatus: typeof fetchServerStatus;
|
|
45
|
+
fetchServerStatuses: typeof fetchServerStatuses;
|
|
44
46
|
fetchShips: typeof fetchShips;
|
|
45
47
|
fetchShipList: typeof fetchShipList;
|
|
46
48
|
joinShip: typeof joinShip;
|
package/docs/NODE_API.md
CHANGED
|
@@ -108,7 +108,22 @@ Scrapes the current game version string from the site.
|
|
|
108
108
|
function fetchServers(): Promise<Server[]>;
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
Scrapes and returns
|
|
111
|
+
Scrapes and returns game servers.
|
|
112
|
+
### `Dredless.fetchServerStatus(server)`
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
function fetchServerStatus(server: ServerRef): Promise<{ playerCount: number; maxPlayerCount: number; ping: number }>;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Pings the server and returns the current player counts and measured response time in milliseconds.
|
|
119
|
+
|
|
120
|
+
### `Dredless.fetchServerStatuses()`
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
function fetchServerStatuses(): Promise<Server[]>;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Fetches status for every server and returns server objects with updated `playerCount`, `maxPlayerCount`, and `ping` fields.
|
|
112
127
|
|
|
113
128
|
### `Dredless.fetchShips(session, server)`
|
|
114
129
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dredless",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A fully-featured and from-scratch headless drednot.io client implementation written in pure js.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/certainhuman/dredless#readme",
|
package/src/browser.d.ts
CHANGED
|
@@ -76,6 +76,8 @@ export {
|
|
|
76
76
|
decompressLz4Frame,
|
|
77
77
|
fetchNoticeVersion,
|
|
78
78
|
fetchGameVersion,
|
|
79
|
+
fetchServerStatus,
|
|
80
|
+
fetchServerStatuses,
|
|
79
81
|
fetchServers
|
|
80
82
|
} from "./index.js";
|
|
81
83
|
|
|
@@ -199,7 +201,7 @@ export interface DredlessBrowserNamespace {
|
|
|
199
201
|
fetchAccountStatus: typeof fetchAccountStatus;
|
|
200
202
|
fetchNoticeVersion: typeof import("./index.js").fetchNoticeVersion;
|
|
201
203
|
fetchGameVersion: typeof import("./index.js").fetchGameVersion;
|
|
202
|
-
fetchServers: typeof import("./index.js").fetchServers;
|
|
204
|
+
fetchServers: typeof import("./index.js").fetchServers;`r`n fetchServerStatus: typeof import("./index.js").fetchServerStatus;`r`n fetchServerStatuses: typeof import("./index.js").fetchServerStatuses;
|
|
203
205
|
fetchShips: typeof fetchShips;
|
|
204
206
|
fetchShipList: typeof fetchShipList;
|
|
205
207
|
joinShip: typeof joinShip;
|
package/src/browser.js
CHANGED
|
@@ -66,7 +66,7 @@ export {
|
|
|
66
66
|
} from "./protocol/outbound/ui-config.js";
|
|
67
67
|
export {decryptPayload} from "./crypto/chacha.js";
|
|
68
68
|
export {decompressLz4Frame} from "./compression/lz4.js";
|
|
69
|
-
export {fetchNoticeVersion, fetchGameVersion, fetchServers} from "./network/servers.js";
|
|
69
|
+
export {fetchNoticeVersion, fetchGameVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
70
70
|
export {fetchShips as fetchShipsWithSession, fetchShipList as fetchShipListWithSession} from "./network/ships.js";
|
|
71
71
|
export {
|
|
72
72
|
BrowserSession,
|
|
@@ -88,7 +88,7 @@ export {
|
|
|
88
88
|
|
|
89
89
|
import {Connection} from "./network/connection.js";
|
|
90
90
|
import {DredlessClient} from "./client/index.js";
|
|
91
|
-
import {fetchGameVersion, fetchNoticeVersion, fetchServers} from "./network/servers.js";
|
|
91
|
+
import {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
92
92
|
import {
|
|
93
93
|
BrowserSession,
|
|
94
94
|
browserSession,
|
|
@@ -121,6 +121,8 @@ export const DredlessBrowser = {
|
|
|
121
121
|
fetchAccountStatus,
|
|
122
122
|
fetchNoticeVersion,
|
|
123
123
|
fetchGameVersion,
|
|
124
|
+
fetchServerStatus,
|
|
125
|
+
fetchServerStatuses,
|
|
124
126
|
fetchServers,
|
|
125
127
|
fetchShips,
|
|
126
128
|
fetchShipList: fetchShipListForBrowser,
|
package/src/index.d.ts
CHANGED
|
@@ -2,9 +2,6 @@ export interface Server {
|
|
|
2
2
|
index: number;
|
|
3
3
|
domain: string;
|
|
4
4
|
description: string;
|
|
5
|
-
playerCount: number;
|
|
6
|
-
maxPlayerCount: number;
|
|
7
|
-
ping: number | null;
|
|
8
5
|
}
|
|
9
6
|
|
|
10
7
|
export interface Ship {
|
|
@@ -31,6 +28,12 @@ export type ShipSpec =
|
|
|
31
28
|
| { type: "new"; name?: string | null; color?: string | null }
|
|
32
29
|
| { type: "invite"; code: string };
|
|
33
30
|
|
|
31
|
+
export interface ServerStatus {
|
|
32
|
+
playerCount: number;
|
|
33
|
+
maxPlayerCount: number;
|
|
34
|
+
ping: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
34
37
|
export type ServerRef = number | Server;
|
|
35
38
|
export type ShipRef = number | string | Ship | ShipSpec | null;
|
|
36
39
|
export type ShipPrivacy = 0 | 1 | boolean | "public" | "private";
|
|
@@ -2248,6 +2251,10 @@ export function fetchGameVersion(): Promise<string>;
|
|
|
2248
2251
|
|
|
2249
2252
|
export function fetchServers(): Promise<Server[]>;
|
|
2250
2253
|
|
|
2254
|
+
export function fetchServerStatus(server: ServerRef): Promise<ServerStatus>;
|
|
2255
|
+
|
|
2256
|
+
export function fetchServerStatuses(): Promise<(Server & ServerStatus)[]>;
|
|
2257
|
+
|
|
2251
2258
|
export function fetchShips(session: Session, server: ServerRef): Promise<Ship[]>;
|
|
2252
2259
|
|
|
2253
2260
|
export function fetchShipList(session: Session, server: ServerRef): Promise<ShipList>;
|
|
@@ -2273,6 +2280,8 @@ export interface DredlessNamespace {
|
|
|
2273
2280
|
fetchNoticeVersion: typeof fetchNoticeVersion;
|
|
2274
2281
|
fetchGameVersion: typeof fetchGameVersion;
|
|
2275
2282
|
fetchServers: typeof fetchServers;
|
|
2283
|
+
fetchServerStatus: typeof fetchServerStatus;
|
|
2284
|
+
fetchServerStatuses: typeof fetchServerStatuses;
|
|
2276
2285
|
fetchShips: typeof fetchShips;
|
|
2277
2286
|
fetchShipList: typeof fetchShipList;
|
|
2278
2287
|
joinShip: typeof joinShip;
|
|
@@ -2280,6 +2289,5 @@ export interface DredlessNamespace {
|
|
|
2280
2289
|
startNewShip: typeof startNewShip;
|
|
2281
2290
|
joinInvite: typeof joinInvite;
|
|
2282
2291
|
}
|
|
2283
|
-
|
|
2284
2292
|
export const Dredless: DredlessNamespace;
|
|
2285
2293
|
export default Dredless;
|
package/src/index.js
CHANGED
|
@@ -81,7 +81,7 @@ export {decompressLz4Frame} from "./compression/lz4.js";
|
|
|
81
81
|
import {AnonSession, createAnonSession, createAnonToken, createSession, Session} from "./network/session.js";
|
|
82
82
|
import {Connection} from "./network/connection.js";
|
|
83
83
|
import {DredlessClient} from "./client/index.js";
|
|
84
|
-
import {fetchGameVersion, fetchNoticeVersion, fetchServers} from "./network/servers.js";
|
|
84
|
+
import {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
85
85
|
import {fetchShipList, fetchShips} from "./network/ships.js";
|
|
86
86
|
|
|
87
87
|
async function sessionOrAnon(session) {
|
|
@@ -114,6 +114,8 @@ export const Dredless = {
|
|
|
114
114
|
createAnonToken,
|
|
115
115
|
fetchNoticeVersion,
|
|
116
116
|
fetchGameVersion,
|
|
117
|
+
fetchServerStatus,
|
|
118
|
+
fetchServerStatuses,
|
|
117
119
|
fetchServers,
|
|
118
120
|
fetchShips,
|
|
119
121
|
fetchShipList,
|
package/src/network/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export {Connection} from "./connection.js";
|
|
2
|
-
export {fetchGameVersion, fetchNoticeVersion, fetchServers, resolveServer} from "./servers.js";
|
|
2
|
+
export {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers, resolveServer} from "./servers.js";
|
|
3
3
|
export {fetchShips, fetchShipList, createShipSpec, createInviteShipSpec, shipRef} from "./ships.js";
|
|
4
4
|
export {Session, AnonSession, createSession, createAnonSession, createAnonToken} from "./session.js";
|
package/src/network/servers.d.ts
CHANGED
package/src/network/servers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {DEFAULT_BASE_URL} from "../constants.js";
|
|
2
|
-
import {hostName, normalizeBaseUrl} from "../runtime.js";
|
|
2
|
+
import {getWebSocket, hostName, normalizeBaseUrl} from "../runtime.js";
|
|
3
3
|
import {HttpClient} from "./http.js";
|
|
4
4
|
|
|
5
5
|
const cache = new Map();
|
|
@@ -56,6 +56,56 @@ class ServerDirectory {
|
|
|
56
56
|
|
|
57
57
|
export const fetchGameVersion = (baseUrl = DEFAULT_BASE_URL) => new ServerDirectory(baseUrl).version();
|
|
58
58
|
export const fetchServers = (baseUrl = DEFAULT_BASE_URL) => new ServerDirectory(baseUrl).servers();
|
|
59
|
+
export async function fetchServerStatus(server, baseUrl = DEFAULT_BASE_URL) {
|
|
60
|
+
const resolved = await resolveServer(server, baseUrl);
|
|
61
|
+
if (!resolved?.domain) throw new Error(`Unable to resolve server ${serverId(server)}`);
|
|
62
|
+
const WebSocket = await getWebSocket();
|
|
63
|
+
const startedAt = Date.now();
|
|
64
|
+
const socket = new WebSocket(`wss://${resolved.domain}:4000/`);
|
|
65
|
+
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
let settled = false;
|
|
68
|
+
const finish = (callback, value) => {
|
|
69
|
+
if (settled) return;
|
|
70
|
+
settled = true;
|
|
71
|
+
clearTimeout(timeout);
|
|
72
|
+
callback(value);
|
|
73
|
+
if (socket.readyState === 0 || socket.readyState === 1) socket.close();
|
|
74
|
+
};
|
|
75
|
+
const timeout = setTimeout(() => finish(reject, new Error(`Timed out fetching status for ${resolved.domain}`)), 10000);
|
|
76
|
+
const onOpen = () => socket.send("yo");
|
|
77
|
+
const onMessage = async (event) => {
|
|
78
|
+
try {
|
|
79
|
+
const data = JSON.parse(await websocketText(event?.data ?? event));
|
|
80
|
+
const playerCount = Number(data.player_count);
|
|
81
|
+
const maxPlayerCount = Number(data.player_max);
|
|
82
|
+
if (!Number.isFinite(playerCount) || !Number.isFinite(maxPlayerCount)) throw new Error("Invalid server status response");
|
|
83
|
+
finish(resolve, {playerCount, maxPlayerCount, ping: Date.now() - startedAt});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
finish(reject, new Error(`Invalid status response from ${resolved.domain}: ${error.message}`));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const onError = (event) => finish(reject, event?.error || new Error(`WebSocket error while fetching ${resolved.domain}`));
|
|
89
|
+
if (typeof socket.on === "function") {
|
|
90
|
+
socket.on("open", onOpen);
|
|
91
|
+
socket.on("message", onMessage);
|
|
92
|
+
socket.on("error", onError);
|
|
93
|
+
} else if (typeof socket.addEventListener === "function") {
|
|
94
|
+
socket.addEventListener("open", onOpen);
|
|
95
|
+
socket.addEventListener("message", onMessage);
|
|
96
|
+
socket.addEventListener("error", onError);
|
|
97
|
+
} else {
|
|
98
|
+
socket.onopen = onOpen;
|
|
99
|
+
socket.onmessage = onMessage;
|
|
100
|
+
socket.onerror = onError;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function fetchServerStatuses(baseUrl = DEFAULT_BASE_URL) {
|
|
106
|
+
const servers = await fetchServers(baseUrl);
|
|
107
|
+
return Promise.all(servers.map(async (server) => ({...server, ...await fetchServerStatus(server, baseUrl)})));
|
|
108
|
+
}
|
|
59
109
|
|
|
60
110
|
export async function fetchNoticeVersion(baseUrl = DEFAULT_BASE_URL) {
|
|
61
111
|
const response = await new HttpClient({baseUrl}).request("index.html");
|
|
@@ -128,6 +178,13 @@ function parseServerInfo(text, baseUrl) {
|
|
|
128
178
|
};
|
|
129
179
|
}
|
|
130
180
|
|
|
181
|
+
async function websocketText(data) {
|
|
182
|
+
if (typeof data === "string") return data;
|
|
183
|
+
if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
|
|
184
|
+
if (ArrayBuffer.isView(data)) return new TextDecoder().decode(data);
|
|
185
|
+
if (typeof data?.text === "function") return data.text();
|
|
186
|
+
return String(data);
|
|
187
|
+
}
|
|
131
188
|
function server(index, domain, description) {
|
|
132
|
-
return {index, domain, description
|
|
189
|
+
return {index, domain, description};
|
|
133
190
|
}
|