max-account-api 0.1.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/LICENSE +21 -0
- package/README.md +328 -0
- package/dist/auth.d.ts +85 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +204 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +724 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1601 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/media.d.ts +67 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +233 -0
- package/dist/media.js.map +1 -0
- package/dist/opcodes.d.ts +435 -0
- package/dist/opcodes.d.ts.map +1 -0
- package/dist/opcodes.js +456 -0
- package/dist/opcodes.js.map +1 -0
- package/dist/qr-bind.d.ts +60 -0
- package/dist/qr-bind.d.ts.map +1 -0
- package/dist/qr-bind.js +102 -0
- package/dist/qr-bind.js.map +1 -0
- package/dist/raw-transport.d.ts +125 -0
- package/dist/raw-transport.d.ts.map +1 -0
- package/dist/raw-transport.js +510 -0
- package/dist/raw-transport.js.map +1 -0
- package/dist/storage.d.ts +56 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +70 -0
- package/dist/storage.js.map +1 -0
- package/dist/transport.d.ts +52 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +193 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +1141 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface StoredSession {
|
|
2
|
+
deviceId: string;
|
|
3
|
+
/**
|
|
4
|
+
* Stable per-install UUID. The mobile MAX client sends this in op 6 HELLO as
|
|
5
|
+
* `mt_instanceid` — gating phone-auth and other ANDROID/IOS-only flows.
|
|
6
|
+
* Auto-generated on first session load if missing.
|
|
7
|
+
*/
|
|
8
|
+
mtInstanceId?: string;
|
|
9
|
+
/**
|
|
10
|
+
* 16-char hex device ID used by the mobile binary transport. Different from
|
|
11
|
+
* the WS-side UUID `deviceId` (kept for back-compat) — the server's HELLO
|
|
12
|
+
* template embeds this verbatim. Auto-generated on first load.
|
|
13
|
+
*/
|
|
14
|
+
mobileDeviceId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Web-bound LOGIN token used by the WS transport (`MaxClient`). For
|
|
17
|
+
* phone-auth users this is produced by `qrBindWebSession()` —
|
|
18
|
+
* `MaxClient.loginWithPhone()` does the bind automatically.
|
|
19
|
+
*/
|
|
20
|
+
loginToken?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Mobile-bound LOGIN token from phone-auth (op 17/18 [+ op 115] → op 19).
|
|
23
|
+
* Stored separately because it is **not** WS-compatible — only
|
|
24
|
+
* `RawTransport.mobileLogin()` accepts it. Useful for power-users who
|
|
25
|
+
* want to call mobile-only ops.
|
|
26
|
+
*/
|
|
27
|
+
mobileLoginToken?: string;
|
|
28
|
+
webToken?: string;
|
|
29
|
+
webTokenExpiresAt?: number;
|
|
30
|
+
ownerId?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SessionStore {
|
|
33
|
+
load(): Promise<StoredSession>;
|
|
34
|
+
save(s: StoredSession): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* JSON file session store. Holds deviceId + auth tokens between runs.
|
|
38
|
+
* Default path: ./.max-session.json (relative to process.cwd()).
|
|
39
|
+
*
|
|
40
|
+
* For production, prefer storing tokens in a secret manager (env, Vault, etc.)
|
|
41
|
+
* and implement SessionStore yourself.
|
|
42
|
+
*/
|
|
43
|
+
export declare class FileSessionStore implements SessionStore {
|
|
44
|
+
private readonly file;
|
|
45
|
+
private cache;
|
|
46
|
+
constructor(file?: string);
|
|
47
|
+
load(): Promise<StoredSession>;
|
|
48
|
+
save(s: StoredSession): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
export declare class MemorySessionStore implements SessionStore {
|
|
51
|
+
private state;
|
|
52
|
+
constructor(initial?: Partial<StoredSession>);
|
|
53
|
+
load(): Promise<StoredSession>;
|
|
54
|
+
save(s: StoredSession): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IAEvC,OAAO,CAAC,QAAQ,CAAC,IAAI;IADjC,OAAO,CAAC,KAAK,CAA8B;gBACd,IAAI,SAAmD;IAE9E,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC;IA0B9B,IAAI,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAI5C;AAED,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,KAAK,CAAgB;gBACjB,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAQtC,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC;IAG9B,IAAI,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID, randomBytes } from 'node:crypto';
|
|
4
|
+
function freshMobileDeviceId() {
|
|
5
|
+
return randomBytes(8).toString('hex');
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* JSON file session store. Holds deviceId + auth tokens between runs.
|
|
9
|
+
* Default path: ./.max-session.json (relative to process.cwd()).
|
|
10
|
+
*
|
|
11
|
+
* For production, prefer storing tokens in a secret manager (env, Vault, etc.)
|
|
12
|
+
* and implement SessionStore yourself.
|
|
13
|
+
*/
|
|
14
|
+
export class FileSessionStore {
|
|
15
|
+
file;
|
|
16
|
+
cache = null;
|
|
17
|
+
constructor(file = path.resolve(process.cwd(), '.max-session.json')) {
|
|
18
|
+
this.file = file;
|
|
19
|
+
}
|
|
20
|
+
async load() {
|
|
21
|
+
if (this.cache)
|
|
22
|
+
return this.cache;
|
|
23
|
+
try {
|
|
24
|
+
const raw = await fs.readFile(this.file, 'utf-8');
|
|
25
|
+
this.cache = JSON.parse(raw);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
this.cache = {
|
|
29
|
+
deviceId: randomUUID(),
|
|
30
|
+
mtInstanceId: randomUUID(),
|
|
31
|
+
mobileDeviceId: freshMobileDeviceId(),
|
|
32
|
+
};
|
|
33
|
+
await this.save(this.cache);
|
|
34
|
+
}
|
|
35
|
+
let mutated = false;
|
|
36
|
+
if (!this.cache.mtInstanceId) {
|
|
37
|
+
this.cache.mtInstanceId = randomUUID();
|
|
38
|
+
mutated = true;
|
|
39
|
+
}
|
|
40
|
+
if (!this.cache.mobileDeviceId) {
|
|
41
|
+
this.cache.mobileDeviceId = freshMobileDeviceId();
|
|
42
|
+
mutated = true;
|
|
43
|
+
}
|
|
44
|
+
if (mutated)
|
|
45
|
+
await this.save(this.cache);
|
|
46
|
+
return this.cache;
|
|
47
|
+
}
|
|
48
|
+
async save(s) {
|
|
49
|
+
this.cache = s;
|
|
50
|
+
await fs.writeFile(this.file, JSON.stringify(s, null, 2), 'utf-8');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export class MemorySessionStore {
|
|
54
|
+
state;
|
|
55
|
+
constructor(initial) {
|
|
56
|
+
this.state = {
|
|
57
|
+
deviceId: initial?.deviceId ?? randomUUID(),
|
|
58
|
+
mtInstanceId: initial?.mtInstanceId ?? randomUUID(),
|
|
59
|
+
mobileDeviceId: initial?.mobileDeviceId ?? freshMobileDeviceId(),
|
|
60
|
+
...initial,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async load() {
|
|
64
|
+
return this.state;
|
|
65
|
+
}
|
|
66
|
+
async save(s) {
|
|
67
|
+
this.state = s;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,mBAAmB;IAC1B,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAuCD;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAEE;IADrB,KAAK,GAAyB,IAAI,CAAC;IAC3C,YAA6B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC;QAAvD,SAAI,GAAJ,IAAI,CAAmD;IAAG,CAAC;IAExF,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,KAAK,GAAG;gBACX,QAAQ,EAAE,UAAU,EAAE;gBACtB,YAAY,EAAE,UAAU,EAAE;gBAC1B,cAAc,EAAE,mBAAmB,EAAE;aACtC,CAAC;YACF,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,UAAU,EAAE,CAAC;YACvC,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,mBAAmB,EAAE,CAAC;YAClD,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,OAAO;YAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAgB;QACzB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;CACF;AAED,MAAM,OAAO,kBAAkB;IACrB,KAAK,CAAgB;IAC7B,YAAY,OAAgC;QAC1C,IAAI,CAAC,KAAK,GAAG;YACX,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE;YAC3C,YAAY,EAAE,OAAO,EAAE,YAAY,IAAI,UAAU,EAAE;YACnD,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,mBAAmB,EAAE;YAChE,GAAG,OAAO;SACX,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAgB;QACzB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { WireFrame } from './types.js';
|
|
3
|
+
export interface TransportOptions {
|
|
4
|
+
url: string;
|
|
5
|
+
pingIntervalMs?: number;
|
|
6
|
+
reconnectDelayMs?: number;
|
|
7
|
+
maxReconnectDelayMs?: number;
|
|
8
|
+
requestTimeoutMs?: number;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Low-level WebSocket transport.
|
|
13
|
+
*
|
|
14
|
+
* Owns:
|
|
15
|
+
* - connection lifecycle (auto-reconnect with exponential backoff)
|
|
16
|
+
* - seq numbering for outgoing requests
|
|
17
|
+
* - request/response correlation via (opcode, seq)
|
|
18
|
+
* - server-pushed events (cmd:0 from server) → ack with cmd:1 + emit `push`
|
|
19
|
+
*
|
|
20
|
+
* Higher-level handlers subscribe to `push` and call `request()` to send commands.
|
|
21
|
+
*/
|
|
22
|
+
export declare class Transport extends EventEmitter {
|
|
23
|
+
private ws;
|
|
24
|
+
private outgoingSeq;
|
|
25
|
+
private pending;
|
|
26
|
+
private pingTimer;
|
|
27
|
+
private reconnectAttempts;
|
|
28
|
+
private closedByUser;
|
|
29
|
+
private readonly opts;
|
|
30
|
+
constructor(opts: TransportOptions);
|
|
31
|
+
connect(): Promise<void>;
|
|
32
|
+
close(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Send a request frame and await matched response (cmd:1, same opcode+seq).
|
|
35
|
+
*/
|
|
36
|
+
request<TRes = unknown>(opcode: number, payload?: unknown): Promise<TRes>;
|
|
37
|
+
/**
|
|
38
|
+
* Send a "fire-and-forget" frame with custom cmd (used for acking server pushes).
|
|
39
|
+
*/
|
|
40
|
+
sendRaw(frame: Omit<WireFrame, 'ver'>): void;
|
|
41
|
+
private key;
|
|
42
|
+
private onMessage;
|
|
43
|
+
/**
|
|
44
|
+
* Ack a server push with a cmd:1 frame mirroring its opcode+seq.
|
|
45
|
+
*/
|
|
46
|
+
ackPush(frame: WireFrame, payload?: unknown): void;
|
|
47
|
+
private onClose;
|
|
48
|
+
private scheduleReconnect;
|
|
49
|
+
private startPing;
|
|
50
|
+
private stopPing;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AASD;;;;;;;;;;GAUG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqF;gBAE9F,IAAI,EAAE,gBAAgB;IAWlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiCxB,KAAK,IAAI,IAAI;IAYb;;OAEG;IACH,OAAO,CAAC,IAAI,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCzE;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,IAAI;IAK5C,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,SAAS;IAuCjB;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IASlD,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,QAAQ;CAMjB"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { Cmd, PROTOCOL_VERSION } from './opcodes.js';
|
|
4
|
+
/**
|
|
5
|
+
* Low-level WebSocket transport.
|
|
6
|
+
*
|
|
7
|
+
* Owns:
|
|
8
|
+
* - connection lifecycle (auto-reconnect with exponential backoff)
|
|
9
|
+
* - seq numbering for outgoing requests
|
|
10
|
+
* - request/response correlation via (opcode, seq)
|
|
11
|
+
* - server-pushed events (cmd:0 from server) → ack with cmd:1 + emit `push`
|
|
12
|
+
*
|
|
13
|
+
* Higher-level handlers subscribe to `push` and call `request()` to send commands.
|
|
14
|
+
*/
|
|
15
|
+
export class Transport extends EventEmitter {
|
|
16
|
+
ws = null;
|
|
17
|
+
outgoingSeq = 0;
|
|
18
|
+
pending = new Map();
|
|
19
|
+
pingTimer = null;
|
|
20
|
+
reconnectAttempts = 0;
|
|
21
|
+
closedByUser = false;
|
|
22
|
+
opts;
|
|
23
|
+
constructor(opts) {
|
|
24
|
+
super();
|
|
25
|
+
this.opts = {
|
|
26
|
+
pingIntervalMs: 30_000,
|
|
27
|
+
reconnectDelayMs: 1_000,
|
|
28
|
+
maxReconnectDelayMs: 30_000,
|
|
29
|
+
requestTimeoutMs: 20_000,
|
|
30
|
+
...opts,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
connect() {
|
|
34
|
+
this.closedByUser = false;
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const headers = this.opts.headers ?? {
|
|
37
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36',
|
|
38
|
+
Origin: 'https://web.max.ru',
|
|
39
|
+
};
|
|
40
|
+
const ws = new WebSocket(this.opts.url, { headers });
|
|
41
|
+
this.ws = ws;
|
|
42
|
+
const onceOpen = () => {
|
|
43
|
+
ws.off('error', onceErr);
|
|
44
|
+
this.reconnectAttempts = 0;
|
|
45
|
+
this.emit('open');
|
|
46
|
+
this.startPing();
|
|
47
|
+
resolve();
|
|
48
|
+
};
|
|
49
|
+
const onceErr = (err) => {
|
|
50
|
+
ws.off('open', onceOpen);
|
|
51
|
+
reject(err);
|
|
52
|
+
};
|
|
53
|
+
ws.once('open', onceOpen);
|
|
54
|
+
ws.once('error', onceErr);
|
|
55
|
+
ws.on('message', (data) => this.onMessage(data));
|
|
56
|
+
ws.on('close', (code, reason) => this.onClose(code, reason.toString()));
|
|
57
|
+
ws.on('error', (err) => this.emit('error', err));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
close() {
|
|
61
|
+
this.closedByUser = true;
|
|
62
|
+
this.stopPing();
|
|
63
|
+
this.ws?.close();
|
|
64
|
+
this.ws = null;
|
|
65
|
+
for (const [key, p] of this.pending) {
|
|
66
|
+
clearTimeout(p.timer);
|
|
67
|
+
p.reject(new Error('Transport closed'));
|
|
68
|
+
this.pending.delete(key);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Send a request frame and await matched response (cmd:1, same opcode+seq).
|
|
73
|
+
*/
|
|
74
|
+
request(opcode, payload) {
|
|
75
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
76
|
+
return Promise.reject(new Error('WebSocket is not open'));
|
|
77
|
+
}
|
|
78
|
+
const seq = this.outgoingSeq++;
|
|
79
|
+
const frame = {
|
|
80
|
+
ver: PROTOCOL_VERSION,
|
|
81
|
+
cmd: Cmd.REQUEST,
|
|
82
|
+
seq,
|
|
83
|
+
opcode,
|
|
84
|
+
...(payload !== undefined ? { payload } : {}),
|
|
85
|
+
};
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const timer = setTimeout(() => {
|
|
88
|
+
this.pending.delete(this.key(opcode, seq));
|
|
89
|
+
reject(new Error(`Request timeout: opcode=${opcode} seq=${seq}`));
|
|
90
|
+
}, this.opts.requestTimeoutMs);
|
|
91
|
+
this.pending.set(this.key(opcode, seq), {
|
|
92
|
+
resolve: (p) => resolve(p),
|
|
93
|
+
reject,
|
|
94
|
+
timer,
|
|
95
|
+
opcode,
|
|
96
|
+
});
|
|
97
|
+
this.ws.send(JSON.stringify(frame), (err) => {
|
|
98
|
+
if (err) {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
this.pending.delete(this.key(opcode, seq));
|
|
101
|
+
reject(err);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Send a "fire-and-forget" frame with custom cmd (used for acking server pushes).
|
|
108
|
+
*/
|
|
109
|
+
sendRaw(frame) {
|
|
110
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
111
|
+
return;
|
|
112
|
+
this.ws.send(JSON.stringify({ ver: PROTOCOL_VERSION, ...frame }));
|
|
113
|
+
}
|
|
114
|
+
key(opcode, seq) {
|
|
115
|
+
return `${opcode}:${seq}`;
|
|
116
|
+
}
|
|
117
|
+
onMessage(data) {
|
|
118
|
+
let frame;
|
|
119
|
+
try {
|
|
120
|
+
frame = JSON.parse(data.toString());
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
this.emit('error', new Error(`Bad frame: ${err.message}`));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
this.emit('raw', frame);
|
|
127
|
+
if (frame.cmd === Cmd.RESPONSE) {
|
|
128
|
+
const k = this.key(frame.opcode, frame.seq);
|
|
129
|
+
const p = this.pending.get(k);
|
|
130
|
+
if (p) {
|
|
131
|
+
clearTimeout(p.timer);
|
|
132
|
+
this.pending.delete(k);
|
|
133
|
+
p.resolve(frame.payload);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (frame.cmd === Cmd.ERROR) {
|
|
138
|
+
const k = this.key(frame.opcode, frame.seq);
|
|
139
|
+
const p = this.pending.get(k);
|
|
140
|
+
if (p) {
|
|
141
|
+
clearTimeout(p.timer);
|
|
142
|
+
this.pending.delete(k);
|
|
143
|
+
const errObj = (frame.payload ?? {});
|
|
144
|
+
const msg = errObj.error ? `${errObj.error}${errObj.message ? ': ' + errObj.message : ''}` : 'unknown server error';
|
|
145
|
+
p.reject(new Error(`Server error op=${frame.opcode}: ${msg}`));
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
// Server-pushed event (cmd:0 from server). Emit; consumer decides whether to ack.
|
|
150
|
+
this.emit('push', frame);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Ack a server push with a cmd:1 frame mirroring its opcode+seq.
|
|
154
|
+
*/
|
|
155
|
+
ackPush(frame, payload) {
|
|
156
|
+
this.sendRaw({
|
|
157
|
+
cmd: Cmd.RESPONSE,
|
|
158
|
+
seq: frame.seq,
|
|
159
|
+
opcode: frame.opcode,
|
|
160
|
+
...(payload !== undefined ? { payload } : {}),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
onClose(code, reason) {
|
|
164
|
+
this.stopPing();
|
|
165
|
+
this.emit('close', code, reason);
|
|
166
|
+
if (this.closedByUser)
|
|
167
|
+
return;
|
|
168
|
+
this.scheduleReconnect();
|
|
169
|
+
}
|
|
170
|
+
scheduleReconnect() {
|
|
171
|
+
const attempt = ++this.reconnectAttempts;
|
|
172
|
+
const delay = Math.min(this.opts.reconnectDelayMs * 2 ** Math.min(attempt - 1, 6), this.opts.maxReconnectDelayMs);
|
|
173
|
+
setTimeout(() => {
|
|
174
|
+
if (this.closedByUser)
|
|
175
|
+
return;
|
|
176
|
+
this.emit('reconnect', attempt);
|
|
177
|
+
this.connect().catch((err) => this.emit('error', err));
|
|
178
|
+
}, delay);
|
|
179
|
+
}
|
|
180
|
+
startPing() {
|
|
181
|
+
this.stopPing();
|
|
182
|
+
this.pingTimer = setInterval(() => {
|
|
183
|
+
this.request(1, { interactive: true }).catch((err) => this.emit('error', err));
|
|
184
|
+
}, this.opts.pingIntervalMs);
|
|
185
|
+
}
|
|
186
|
+
stopPing() {
|
|
187
|
+
if (this.pingTimer) {
|
|
188
|
+
clearInterval(this.pingTimer);
|
|
189
|
+
this.pingTimer = null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|