dredless 0.7.0 → 1.0.1

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.
Files changed (40) hide show
  1. package/README.md +22 -58
  2. package/dist/browser/dredless.global.js +794 -98
  3. package/dist/browser/dredless.global.js.map +4 -4
  4. package/docs/ACCOUNT.md +146 -0
  5. package/docs/API_REFERENCE.md +63 -2563
  6. package/docs/BROWSER_API.md +151 -70
  7. package/docs/CLIENT.md +183 -0
  8. package/docs/EVENTS.md +136 -0
  9. package/docs/GETTING_STARTED.md +135 -0
  10. package/docs/MACHINES.md +351 -0
  11. package/docs/MANAGEMENT.md +285 -0
  12. package/docs/NODE_API.md +120 -318
  13. package/docs/PLAYER_INVENTORY.md +235 -0
  14. package/docs/PROTOCOL.md +227 -0
  15. package/docs/README.md +44 -0
  16. package/docs/TROUBLESHOOTING.md +91 -0
  17. package/docs/WORLD_STATE.md +183 -0
  18. package/package.json +1 -2
  19. package/src/browser.d.ts +31 -1
  20. package/src/browser.js +10 -0
  21. package/src/client/core.js +302 -15
  22. package/src/client/domains/index.js +57 -7
  23. package/src/client/index.d.ts +1 -1
  24. package/src/index.d.ts +299 -13
  25. package/src/index.js +10 -0
  26. package/src/network/account.js +182 -0
  27. package/src/network/disconnect.d.ts +2 -0
  28. package/src/network/disconnect.js +53 -0
  29. package/src/network/index.d.ts +1 -0
  30. package/src/network/index.js +1 -0
  31. package/src/network/invites.d.ts +0 -3
  32. package/src/network/invites.js +3 -40
  33. package/src/network/session.d.ts +2 -0
  34. package/src/network/session.js +21 -0
  35. package/src/protocol/outbound/ship-management.d.ts +66 -1
  36. package/src/protocol/outbound/ship-management.js +83 -0
  37. package/src/state/model/decoder.js +70 -10
  38. package/src/state/model/index.d.ts +4 -0
  39. package/src/state/model/state.js +22 -7
  40. package/src/state/world/index.js +27 -1
package/docs/NODE_API.md CHANGED
@@ -1,393 +1,195 @@
1
- # Dredless Node API
1
+ # Node sessions and connections
2
2
 
3
- This document covers the Node-specific top-level API: explicit sessions, anonymous token/session creation, connection descriptors, and convenience start/join helpers.
3
+ [Documentation index](README.md) · [Getting started](GETTING_STARTED.md) · [API reference](API_REFERENCE.md)
4
4
 
5
- Use this entrypoint when you want the multi-session cookie-jar API:
5
+ ## Contents
6
6
 
7
- ```js
8
- import Dredless, {
9
- Session,
10
- AnonSession,
11
- Connection,
12
- DredlessClient
13
- } from "dredless/node";
14
- ```
7
+ - [Imports and sessions](#imports-and-sessions)
8
+ - [Authentication and reuse](#authentication-and-reuse)
9
+ - [Servers and ship lists](#servers-and-ship-lists)
10
+ - [Join, start, and invites](#join-start-and-invites)
11
+ - [Construct a client yourself](#construct-a-client-yourself)
12
+ - [HTTP requests](#http-requests)
13
+ - [Serialization](#serialization)
15
14
 
16
- Normal Node usage:
15
+ ## Imports and sessions
17
16
 
18
17
  ```js
19
- const session = await Dredless.createAnonSession();
20
- const servers = await Dredless.fetchServers();
21
- const ships = await session.fetchShips(servers[0]);
22
- const client = await session.startShip(servers[0], ships[0]);
23
-
24
- await client.whenReady();
25
- ```
26
-
27
- Shared input shapes such as `Server`, `ServerRef`, `Ship`, `ShipRef`, and `ShipSpec` are documented in [API_REFERENCE.md](./API_REFERENCE.md#common-input-types). Shared client/world/entity/domain APIs are also documented in [API_REFERENCE.md](./API_REFERENCE.md).
28
-
29
- ## `Dredless` Namespace
30
-
31
- The default export is a namespace of constructors and convenience factories.
32
-
33
- ```ts
34
- interface DredlessNamespace {
35
- Session: typeof Session;
36
- AnonSession: typeof AnonSession;
37
- Connection: typeof Connection;
38
- DredlessClient: typeof DredlessClient;
39
- createSession: typeof createSession;
40
- createAnonSession: typeof createAnonSession;
41
- createAnonToken: typeof createAnonToken;
42
- fetchNoticeVersion: typeof fetchNoticeVersion;
43
- fetchGameVersion: typeof fetchGameVersion;
44
- fetchServers: typeof fetchServers;
45
- fetchShips: typeof fetchShips;
46
- fetchShipList: typeof fetchShipList;
47
- fetchInviteMetadata: typeof fetchInviteMetadata;
48
- joinShip: typeof joinShip;
49
- startShip: typeof startShip;
50
- startNewShip: typeof startNewShip;
51
- joinInvite: typeof joinInvite;
52
- }
18
+ import Dredless, {Session, AnonSession, Connection, DredlessClient} from "dredless/node";
53
19
  ```
54
20
 
55
- ### `Dredless.createSession(noticeVersion?)`
21
+ The default `Dredless` export contains constructors and the HTTP/start/join convenience functions below. Protocol builders and constants are named exports; they are not all properties of the default namespace.
56
22
 
57
- ```ts
58
- function createSession(noticeVersion?: number | null): Promise<Session>;
59
- ```
60
-
61
- Creates a `Session` using the current game version lookup and optional notice
62
- version. It does not create an anonymous account.
63
-
64
- ### `Dredless.createAnonSession(anonKey?, noticeVersion?, baseUrl?)`
23
+ A `Session` owns an HTTP cookie jar. It does not open a WebSocket until you call a client factory. `AnonSession` adds an `anonKey`. Reuse one session for actions that should use the same identity; use separate sessions for separate identities.
65
24
 
66
25
  ```ts
67
- function createAnonSession(
68
- anonKey?: string | null,
69
- noticeVersion?: number | null,
70
- baseUrl?: string
71
- ): Promise<AnonSession>;
72
- ```
26
+ new Session(gameSession?: string | null, gameVersion?: string | null): Session;
27
+ new AnonSession(gameSession?: string | null, anonKey?: string | null,
28
+ gameVersion?: string | null): AnonSession;
73
29
 
74
- Creates an anonymous session. If `anonKey` is omitted, the library requests one
75
- from the server.
30
+ Dredless.createSession(noticeVersion?: number | null): Promise<Session>;
31
+ Dredless.createAnonSession(anonKey?: string | null, noticeVersion?: number | null,
32
+ baseUrl?: string): Promise<AnonSession>;
33
+ Dredless.createAnonToken(noticeVersion?: number | null, baseUrl?: string): Promise<string>;
76
34
 
77
- Returns an `AnonSession`.
78
-
79
- ### `Dredless.createAnonToken(noticeVersion?, baseUrl?)`
80
-
81
- ```ts
82
- function createAnonToken(
83
- noticeVersion?: number | null,
84
- baseUrl?: string
85
- ): Promise<string>;
35
+ session.fetchAccountStatus(): Promise<unknown>;
86
36
  ```
87
37
 
88
- Requests a new anonymous account token.
38
+ Constructors perform no I/O. `createSession()` fetches account status into a fresh session; it does not log in to a registered account. `createAnonToken()` requests a new anonymous key. `createAnonSession()` uses the supplied key, or requests one when omitted, then fetches status.
89
39
 
90
- ### `Dredless.fetchNoticeVersion()`
40
+ `noticeVersion` is optional; factories attempt to discover it and have a built-in fallback. Alternate `baseUrl` values are origins such as `https://test.drednot.io`. The implementation also accepts `baseUrl` as the third `Session` constructor argument, fourth `AnonSession` argument, and second `createSession()` argument; these overloads are not currently represented in the root declarations.
91
41
 
92
- ```ts
93
- function fetchNoticeVersion(): Promise<number>;
94
- ```
42
+ ## Authentication and reuse
95
43
 
96
- Scrapes the current notice version needed by anon login.
44
+ ### Existing anonymous identity
97
45
 
98
- ### `Dredless.fetchGameVersion()`
46
+ ```js
47
+ import Dredless from "dredless/node";
99
48
 
100
- ```ts
101
- function fetchGameVersion(): Promise<string>;
49
+ const key = process.env.DREDNOT_ANON_KEY;
50
+ if (!key) throw new Error("Set DREDNOT_ANON_KEY to reuse an existing anonymous account");
51
+ const session = await Dredless.createAnonSession(key);
102
52
  ```
103
53
 
104
- Scrapes the current game version string from the site.
54
+ For a new anonymous account, call `createAnonSession()` once and retain `session.anonKey` in your own credential storage. Recreating a session without supplying the key creates a different identity.
105
55
 
106
- ### `Dredless.fetchServers()`
56
+ ### Existing registered session
107
57
 
108
- ```ts
109
- function fetchServers(): Promise<Server[]>;
110
- ```
58
+ Supply your own authenticated `game_session` cookie value. Dredless does not implement the website's identity-provider login flow:
111
59
 
112
- Scrapes and returns game servers.
113
- ### `Dredless.fetchServerStatus(server)`
60
+ ```js
61
+ import {Session} from "dredless/node";
114
62
 
115
- ```ts
116
- function fetchServerStatus(server: ServerRef): Promise<{ playerCount: number; maxPlayerCount: number; ping: number }>;
63
+ const cookie = process.env.DREDNOT_GAME_SESSION;
64
+ if (!cookie) throw new Error("Set DREDNOT_GAME_SESSION");
65
+ const session = new Session(cookie);
66
+ await session.fetchAccountStatus();
67
+ if (!session.account?.is_registered) throw new Error("The session is not a registered account");
117
68
  ```
118
69
 
119
- Pings the server and returns the current player counts and measured response time in milliseconds.
120
-
121
- ### `Dredless.fetchServerStatuses()`
122
-
123
- ```ts
124
- function fetchServerStatuses(): Promise<Server[]>;
125
- ```
70
+ `session.account` is the normalized cached status: `{name, color, game_rank, user_badges, is_registered}` or `null`. `color` is packed RGB. `fetchAccountStatus()` returns the full decoded JSON and updates this cache, along with `geoServer`, `isRegistered`, `upgraded`, `showAds`, `forceTutorial`, and `ban`.
126
71
 
127
- Fetches status for every server and returns server objects with updated `playerCount`, `maxPlayerCount`, and `ping` fields.
72
+ Email, identity service, clan tags, and applied perk ships use [account-page methods](ACCOUNT.md), not `account/status`.
128
73
 
129
- ### `Dredless.fetchShips(session, server)`
74
+ ## Servers and ship lists
130
75
 
131
76
  ```ts
132
- function fetchShips(session: Session, server: ServerRef): Promise<Ship[]>;
133
- ```
134
-
135
- Authenticated convenience wrapper around `session.fetchShips(server)`.
136
-
137
- Ship names in the returned objects are canonical Drednot server data. Leading
138
- and trailing spaces are preserved exactly; callers should not trim them.
77
+ Dredless.fetchServers(): Promise<Server[]>;
78
+ Dredless.fetchServerStatus(server: ServerRef): Promise<ServerStatus>;
79
+ Dredless.fetchServerStatuses(): Promise<(Server & ServerStatus)[]>;
80
+ Dredless.fetchGameVersion(): Promise<string>;
81
+ Dredless.fetchNoticeVersion(): Promise<number>;
139
82
 
140
- ### `Dredless.fetchShipList(session, server)`
83
+ session.fetchShips(server: ServerRef): Promise<Ship[]>;
84
+ session.fetchShipList(server: ServerRef): Promise<ShipList>;
141
85
 
142
- ```ts
143
- function fetchShipList(session: Session, server: ServerRef): Promise<ShipList>;
86
+ Dredless.fetchShips(session: Session, server: ServerRef): Promise<Ship[]>;
87
+ Dredless.fetchShipList(session: Session, server: ServerRef): Promise<ShipList>;
144
88
  ```
145
89
 
146
- Authenticated convenience wrapper around `session.fetchShipList(server)`.
90
+ | Type | Meaning |
91
+ |----------------|---------------------------------------------------------------------------------------------------|
92
+ | `Server` | `{index, domain, description}` |
93
+ | `ServerRef` | A `Server` object or its numeric `index` |
94
+ | `ServerStatus` | `{playerCount, maxPlayerCount, ping}`; ping is milliseconds |
95
+ | `Ship` | Listed ship: `id`, `hexCode`, `name`, `playerCount`, `owned`, `saved`, `color`, `iconUrl`, `time` |
96
+ | `ShipList` | `{ships, playerCount?, maxPlayerCount?, isMuted?}` |
147
97
 
148
- Ship names in the returned objects are canonical Drednot server data. Leading
149
- and trailing spaces are preserved exactly; callers should not trim them.
98
+ `fetchServers()` discovers servers; it does not populate status/ping fields. Discovery metadata is cached per origin for the process/module lifetime; repeated calls do not necessarily refetch the game version or directory. Discovery/status implementations also accept an optional final `baseUrl` argument, although the root declarations omit it. Ship names preserve leading and trailing spaces. Some ship metadata fields are nullable; inspect [declared shapes](../src/index.d.ts) when persisting results.
150
99
 
151
- ### `Dredless.fetchInviteMetadata(invite, options?)`
100
+ ## Join, start, and invites
152
101
 
153
102
  ```ts
154
- function fetchInviteMetadata(
155
- invite: string | URL,
156
- options?: { includeColor?: boolean }
157
- ): Promise<InviteMetadata>;
158
- ```
103
+ session.joinShip(server: ServerRef, ship?: ShipRef): Promise<DredlessClient>;
104
+ session.startShip(server: ServerRef, ship?: ShipRef): Promise<DredlessClient>;
105
+ session.startNewShip(server: ServerRef, name?: string, color?: string): Promise<DredlessClient>;
106
+ session.joinInvite(server: ServerRef, code: string): Promise<DredlessClient>;
159
107
 
160
- Fetches and parses an invite page. The returned ship name preserves leading
161
- and trailing spaces exactly as returned by Drednot. Set `includeColor: true`
162
- to sample the preview image’s top-left pixel; otherwise no image is fetched.
163
-
164
- ### `Dredless.joinShip(server, ship?, session?)`
165
-
166
- ```ts
167
- function joinShip(
168
- server: ServerRef,
169
- ship?: ShipRef,
170
- session?: Session | null
171
- ): Promise<DredlessClient>;
108
+ Dredless.joinShip(server: ServerRef, ship?: ShipRef, session?: Session | null): Promise<DredlessClient>;
109
+ Dredless.startShip(server: ServerRef, ship?: ShipRef, session?: Session | null): Promise<DredlessClient>;
110
+ Dredless.startNewShip(server: ServerRef, name?: string, color?: string,
111
+ session?: Session | null): Promise<DredlessClient>;
112
+ Dredless.joinInvite(server: ServerRef, code: string, session?: Session | null): Promise<DredlessClient>;
172
113
  ```
173
114
 
174
- Starts a websocket client using `never_load: true`. This is useful when you need
175
- to join without loading the full ship world.
115
+ | Method | Choose it when… |
116
+ |----------------|-------------------------------------------------------------------------------|
117
+ | `joinShip` | The ship is active; joining must not load a saved ship (`never_load: true`) |
118
+ | `startShip` | Joining may need to load/start the saved ship (`never_load: false`) |
119
+ | `startNewShip` | You intend to create a new ship; accepts a name and color such as `"#de9797"` |
120
+ | `joinInvite` | You have an invite code; accepts the code segment, not the URL |
176
121
 
177
- If `session` is omitted, an anonymous session is created.
122
+ The join/start distinction concerns loading a saved ship on the server. It is not a switch for partial versus full client world decoding. A `4007` rejection from `joinShip()` can mean the saved ship needs `startShip()`.
178
123
 
179
- ### `Dredless.startShip(server, ship?, session?)`
124
+ All client factories wait for the ready packet. [Lifecycle](CLIENT.md#completion-and-readiness) explains state availability and cleanup. Top-level factories create an anonymous session when `session` is omitted; pass your session explicitly to retain your identity.
180
125
 
181
126
  ```ts
182
- function startShip(
183
- server: ServerRef,
184
- ship?: ShipRef,
185
- session?: Session | null
186
- ): Promise<DredlessClient>;
127
+ type ShipRef = number | string | Ship | ShipSpec | null;
128
+ type ShipSpec =
129
+ | {type: "join_or_load"; id: number | string}
130
+ | {type: "new"; name?: string | null; color?: string | null}
131
+ | {type: "invite"; code: string};
187
132
  ```
188
133
 
189
- Starts a websocket client using normal world loading.
190
-
191
- If `session` is omitted, an anonymous session is created.
134
+ Prefer a `Ship` object obtained from that server's list, or an explicit `ShipSpec`. Strings pass through as server ship selectors; do not assume every ID in every API uses the same format. Omitted/null ships use the method's default selection behavior.
192
135
 
193
- ### `Dredless.startNewShip(server, name?, color?, session?)`
136
+ ### Read an invite preview
194
137
 
195
138
  ```ts
196
- function startNewShip(
197
- server: ServerRef,
198
- name?: string,
199
- color?: string,
200
- session?: Session | null
201
- ): Promise<DredlessClient>;
139
+ Dredless.fetchInviteMetadata(invite: string | URL,
140
+ options?: {fetchImpl?: typeof fetch}): Promise<InviteMetadata>;
202
141
  ```
203
142
 
204
- Creates/starts a new ship and returns a live client.
143
+ This reads the public invite page without joining. It returns `{shipId, name, previewImageUrl, hostname, inviteCode}`. It does not fetch the preview image. Consumers can use `previewImageUrl` to implement their own image processing. Names preserve spacing. See [protocol tools](PROTOCOL.md#http-and-invite-tools) for the named parser export.
205
144
 
206
- ### `Dredless.joinInvite(server, code, session?)`
145
+ ## Construct a client yourself
207
146
 
208
- ```ts
209
- function joinInvite(
210
- server: ServerRef,
211
- code: string,
212
- session?: Session | null
213
- ): Promise<DredlessClient>;
214
- ```
215
-
216
- Joins through an invite code and returns a live client.
217
-
218
-
219
- ## `Session`
220
-
221
- `Session` represents an authenticated HTTP session and owns cookies, account
222
- status, ship list fetches, and `/join`.
147
+ Use connection factories when you need listeners installed before connection:
223
148
 
224
149
  ```ts
225
- class Session {
226
- constructor(gameSession?: string | null, gameVersion?: string | null);
227
-
228
- baseUrl: string;
229
- cookies: Map<string, string>;
230
- gameVersion: string | null;
231
- account: Account | null;
232
- geoServer: number | null;
233
- upgraded: boolean;
234
- isRegistered: boolean;
235
- showAds: boolean;
236
- forceTutorial: boolean;
237
- ban: unknown;
238
-
239
- get gameSession(): string;
240
- get gameToken(): string;
241
- get noticeVersion(): number | string | null;
242
- set noticeVersion(value: number | string | null);
243
-
244
- request(path: string, init?: RequestInit & {
245
- body?: BodyInit | Record<string, unknown> | null
246
- }): Promise<Response>;
247
-
248
- fetchAccountStatus(): Promise<unknown>;
249
- fetchShips(server: ServerRef): Promise<Ship[]>;
250
- fetchShipList(server: ServerRef): Promise<ShipList>;
251
-
252
- joinShipConnection(server: ServerRef, ship?: ShipRef): Promise<Connection>;
253
- startShipConnection(server: ServerRef, ship?: ShipRef): Promise<Connection>;
254
- startNewShipConnection(
255
- server: ServerRef,
256
- name?: string,
257
- color?: string
258
- ): Promise<Connection>;
259
- joinInviteConnection(server: ServerRef, code: string): Promise<Connection>;
260
-
261
- joinShip(server: ServerRef, ship?: ShipRef): Promise<DredlessClient>;
262
- startShip(server: ServerRef, ship?: ShipRef): Promise<DredlessClient>;
263
- startNewShip(server: ServerRef, name?: string, color?: string): Promise<DredlessClient>;
264
- joinInvite(server: ServerRef, code: string): Promise<DredlessClient>;
265
-
266
- toJSON(): SessionSnapshot;
267
- }
268
- ```
269
-
270
- ### `new Session(gameSession?, gameVersion?)`
271
-
272
- Constructs an existing session wrapper. Does not perform network I/O.
273
-
274
- ### `session.request(path, init?)`
275
-
276
- Authenticated HTTP helper. The `path` is relative to `session.baseUrl` unless a
277
- full URL is supplied by the implementation path handling.
278
-
279
- Input body may be a normal `BodyInit`, an object, or `null`.
280
-
281
- Returns the raw `Response`.
282
-
283
- ### `session.fetchAccountStatus()`
284
-
285
- Fetches and applies account status. Returns the decoded server response as
286
- `unknown` because the live shape is not fully stabilized.
287
-
288
- ### `session.fetchShips(server)`
289
-
290
- Returns `Ship[]`.
291
-
292
- ### `session.fetchShipList(server)`
150
+ session.joinShipConnection(server: ServerRef, ship?: ShipRef): Promise<Connection>;
151
+ session.startShipConnection(server: ServerRef, ship?: ShipRef): Promise<Connection>;
152
+ session.startNewShipConnection(server: ServerRef, name?: string, color?: string): Promise<Connection>;
153
+ session.joinInviteConnection(server: ServerRef, code: string): Promise<Connection>;
293
154
 
294
- Returns `ShipList`.
295
-
296
- ### Connection factories
297
-
298
- These return `Connection` objects and do not open the websocket:
299
-
300
- ```ts
301
- session.joinShipConnection(server, ship?): Promise<Connection>;
302
- session.startShipConnection(server, ship?): Promise<Connection>;
303
- session.startNewShipConnection(server, name?, color?): Promise<Connection>;
304
- session.joinInviteConnection(server, code): Promise<Connection>;
155
+ new Connection(session: Session, gameToken: string, netPort: number,
156
+ serverId: number | Server, server?: Server | null): Connection;
305
157
  ```
306
158
 
307
- Use these when you want to construct `DredlessClient` yourself.
308
-
309
- ### Client factories
159
+ A connection factory performs the HTTP join, returning a descriptor without opening the WebSocket. Constructing `Connection` itself performs no I/O.
310
160
 
311
- These return live `DredlessClient` objects:
161
+ **Fragment:** `session`, `server`, and `code` come from the setup above:
312
162
 
313
- ```ts
314
- session.joinShip(server, ship?): Promise<DredlessClient>;
315
- session.startShip(server, ship?): Promise<DredlessClient>;
316
- session.startNewShip(server, name?, color?): Promise<DredlessClient>;
317
- session.joinInvite(server, code): Promise<DredlessClient>;
318
- ```
319
-
320
- ### `session.toJSON()`
321
-
322
- ```ts
323
- interface SessionSnapshot {
324
- baseUrl: string;
325
- gameSession: string;
326
- gameToken: string;
327
- gameVersion: string | null;
328
- noticeVersion: number | string | null;
329
- cookies: Record<string, string>;
330
- account: Account | null;
331
- geoServer: number | null;
332
- upgraded: boolean;
333
- isRegistered: boolean;
334
- showAds: boolean;
335
- forceTutorial: boolean;
336
- ban: unknown;
337
- anonKey?: string;
163
+ ```js
164
+ const connection = await session.joinInviteConnection(server, code);
165
+ const client = new DredlessClient(connection);
166
+ client.on("error", (error) => console.error(error.message));
167
+ client.on("model", ({world}) => console.log(world.id));
168
+ try {
169
+ await client.whenReady();
170
+ // Keep using the client here, or attach application callbacks.
171
+ } catch (error) {
172
+ client.close();
173
+ throw error;
338
174
  }
339
175
  ```
340
176
 
341
- ## `AnonSession`
177
+ See [client options](CLIENT.md#construction-and-retention) for history limits and offline construction.
178
+
179
+ ## HTTP requests
342
180
 
343
181
  ```ts
344
- class AnonSession extends Session {
345
- constructor(
346
- gameSession?: string | null,
347
- anonKey?: string | null,
348
- gameVersion?: string | null
349
- );
350
-
351
- get anonKey(): string;
352
- }
182
+ session.request(path: string, init?: RequestInit & {body?: unknown}): Promise<Response>;
353
183
  ```
354
184
 
355
- `AnonSession` is a `Session` with anonymous account key handling.
185
+ Paths resolve relative to `session.baseUrl`; an absolute URL is also accepted by the resolver. Requests attach the session cookie jar in Node. Use this authenticated helper for the session's intended origin.
356
186
 
357
- ## `Connection`
187
+ Strings, `ArrayBuffer`, and typed-array views pass through as bodies. Other objects are JSON-stringified; the helper sets JSON content type if none was supplied. It does not implement native Fetch handling for `URLSearchParams`, `FormData`, or `Blob` objects. For a form, pass `new URLSearchParams(fields).toString()` with an explicit form content type.
358
188
 
359
- `Connection` is a no-I/O descriptor for an already joined game session.
189
+ The raw `Response` is returned. Callers of `request()` must check HTTP status themselves; it does not automatically reject on HTTP error codes or merge response cookies. Higher-level session methods do their own status/cookie handling.
360
190
 
361
- ```ts
362
- class Connection {
363
- constructor(
364
- session: Session,
365
- gameToken: string,
366
- netPort: number,
367
- serverId: number | Server,
368
- server?: Server | null
369
- );
370
-
371
- session: Session;
372
- baseUrl: string;
373
- gameToken: string;
374
- netPort: number;
375
- serverId: number;
376
- server: Server | null;
377
-
378
- toJSON(): ConnectionSnapshot;
379
- }
380
- ```
191
+ ## Serialization
381
192
 
382
- ### `connection.toJSON()`
193
+ `session.toJSON()` returns a `SessionSnapshot`: base URL, game session/token, cookies, game/notice versions, account status, and status flags. An anonymous session also includes `anonKey`. `connection.toJSON()` includes its session snapshot.
383
194
 
384
- ```ts
385
- interface ConnectionSnapshot {
386
- baseUrl: string;
387
- gameToken: string;
388
- netPort: number;
389
- serverId: number;
390
- server: Server | null;
391
- session: SessionSnapshot;
392
- }
393
- ```
195
+ These snapshots contain credentials. Store them as credentials rather than logging them as ordinary state. No automatic persistence/restore helper is provided. When restoring a cookie jar yourself, use the snapshot's origin and cookie names, then refresh account status. [Account detail reads](ACCOUNT.md) do not add email or identity data to these snapshots.