morok-bot-sdk 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 (96) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +602 -0
  3. package/README.ru.md +602 -0
  4. package/dist/bot.d.ts +232 -0
  5. package/dist/bot.d.ts.map +1 -0
  6. package/dist/bot.js +558 -0
  7. package/dist/bot.js.map +1 -0
  8. package/dist/crypto/channel-cipher.d.ts +32 -0
  9. package/dist/crypto/channel-cipher.d.ts.map +1 -0
  10. package/dist/crypto/channel-cipher.js +77 -0
  11. package/dist/crypto/channel-cipher.js.map +1 -0
  12. package/dist/crypto/channel-key-store.d.ts +37 -0
  13. package/dist/crypto/channel-key-store.d.ts.map +1 -0
  14. package/dist/crypto/channel-key-store.js +149 -0
  15. package/dist/crypto/channel-key-store.js.map +1 -0
  16. package/dist/crypto/cross-signing.d.ts +57 -0
  17. package/dist/crypto/cross-signing.d.ts.map +1 -0
  18. package/dist/crypto/cross-signing.js +111 -0
  19. package/dist/crypto/cross-signing.js.map +1 -0
  20. package/dist/crypto/file-cipher.d.ts +36 -0
  21. package/dist/crypto/file-cipher.d.ts.map +1 -0
  22. package/dist/crypto/file-cipher.js +61 -0
  23. package/dist/crypto/file-cipher.js.map +1 -0
  24. package/dist/crypto/group-secret-cipher.d.ts +49 -0
  25. package/dist/crypto/group-secret-cipher.d.ts.map +1 -0
  26. package/dist/crypto/group-secret-cipher.js +69 -0
  27. package/dist/crypto/group-secret-cipher.js.map +1 -0
  28. package/dist/crypto/group-secret-store.d.ts +35 -0
  29. package/dist/crypto/group-secret-store.d.ts.map +1 -0
  30. package/dist/crypto/group-secret-store.js +149 -0
  31. package/dist/crypto/group-secret-store.js.map +1 -0
  32. package/dist/crypto/signal.d.ts +81 -0
  33. package/dist/crypto/signal.d.ts.map +1 -0
  34. package/dist/crypto/signal.js +125 -0
  35. package/dist/crypto/signal.js.map +1 -0
  36. package/dist/crypto/stores.d.ts +130 -0
  37. package/dist/crypto/stores.d.ts.map +1 -0
  38. package/dist/crypto/stores.js +314 -0
  39. package/dist/crypto/stores.js.map +1 -0
  40. package/dist/flow/attachments.d.ts +110 -0
  41. package/dist/flow/attachments.d.ts.map +1 -0
  42. package/dist/flow/attachments.js +409 -0
  43. package/dist/flow/attachments.js.map +1 -0
  44. package/dist/flow/conv-cache.d.ts +36 -0
  45. package/dist/flow/conv-cache.d.ts.map +1 -0
  46. package/dist/flow/conv-cache.js +84 -0
  47. package/dist/flow/conv-cache.js.map +1 -0
  48. package/dist/flow/direct.d.ts +109 -0
  49. package/dist/flow/direct.d.ts.map +1 -0
  50. package/dist/flow/direct.js +346 -0
  51. package/dist/flow/direct.js.map +1 -0
  52. package/dist/flow/groups.d.ts +146 -0
  53. package/dist/flow/groups.d.ts.map +1 -0
  54. package/dist/flow/groups.js +768 -0
  55. package/dist/flow/groups.js.map +1 -0
  56. package/dist/flow/prekeys.d.ts +45 -0
  57. package/dist/flow/prekeys.d.ts.map +1 -0
  58. package/dist/flow/prekeys.js +111 -0
  59. package/dist/flow/prekeys.js.map +1 -0
  60. package/dist/flow/receive.d.ts +125 -0
  61. package/dist/flow/receive.d.ts.map +1 -0
  62. package/dist/flow/receive.js +773 -0
  63. package/dist/flow/receive.js.map +1 -0
  64. package/dist/index.d.ts +15 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +6 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/morokbot-file.d.ts +14 -0
  69. package/dist/morokbot-file.d.ts.map +1 -0
  70. package/dist/morokbot-file.js +88 -0
  71. package/dist/morokbot-file.js.map +1 -0
  72. package/dist/ratelimit.d.ts +40 -0
  73. package/dist/ratelimit.d.ts.map +1 -0
  74. package/dist/ratelimit.js +76 -0
  75. package/dist/ratelimit.js.map +1 -0
  76. package/dist/sessions.d.ts +34 -0
  77. package/dist/sessions.d.ts.map +1 -0
  78. package/dist/sessions.js +69 -0
  79. package/dist/sessions.js.map +1 -0
  80. package/dist/state-lock.d.ts +17 -0
  81. package/dist/state-lock.d.ts.map +1 -0
  82. package/dist/state-lock.js +66 -0
  83. package/dist/state-lock.js.map +1 -0
  84. package/dist/transport/http.d.ts +48 -0
  85. package/dist/transport/http.d.ts.map +1 -0
  86. package/dist/transport/http.js +112 -0
  87. package/dist/transport/http.js.map +1 -0
  88. package/dist/transport/ws.d.ts +65 -0
  89. package/dist/transport/ws.d.ts.map +1 -0
  90. package/dist/transport/ws.js +219 -0
  91. package/dist/transport/ws.js.map +1 -0
  92. package/dist/types.d.ts +254 -0
  93. package/dist/types.d.ts.map +1 -0
  94. package/dist/types.js +2 -0
  95. package/dist/types.js.map +1 -0
  96. package/package.json +59 -0
@@ -0,0 +1,112 @@
1
+ import axios from 'axios';
2
+ export class HttpClient {
3
+ config;
4
+ axios;
5
+ jwt = null;
6
+ jwtExpiresAt = 0;
7
+ refreshInFlight = null;
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.axios = axios.create({
11
+ baseURL: config.apiBaseUrl,
12
+ timeout: 30_000,
13
+ validateStatus: (s) => s >= 200 && s < 300,
14
+ maxContentLength: 64 * 1024 * 1024,
15
+ maxBodyLength: 64 * 1024 * 1024,
16
+ });
17
+ this.axios.interceptors.request.use((cfg) => {
18
+ if (this.jwt) {
19
+ cfg.headers = cfg.headers ?? {};
20
+ cfg.headers.Authorization = `Bearer ${this.jwt}`;
21
+ }
22
+ return cfg;
23
+ });
24
+ this.axios.interceptors.response.use((r) => r, async (err) => {
25
+ if (!err.config)
26
+ throw err;
27
+ const status = err.response?.status;
28
+ const cfg = err.config;
29
+ if (status === 401 && !cfg._retried) {
30
+ cfg._retried = true;
31
+ try {
32
+ await this.refresh();
33
+ }
34
+ catch (refreshErr) {
35
+ this.logger?.warn({ err: refreshErr.message }, '[http] JWT refresh failed during 401 retry');
36
+ throw err;
37
+ }
38
+ return this.axios.request(cfg);
39
+ }
40
+ throw err;
41
+ });
42
+ }
43
+ get logger() { return this.config.logger; }
44
+ async refresh() {
45
+ if (this.refreshInFlight)
46
+ return this.refreshInFlight;
47
+ this.refreshInFlight = this.doRefresh()
48
+ .finally(() => { this.refreshInFlight = null; });
49
+ return this.refreshInFlight;
50
+ }
51
+ updateExpiryFromJwt(jwt) {
52
+ try {
53
+ const body = jwt.split('.')[1] ?? '';
54
+ const claims = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
55
+ this.jwtExpiresAt = typeof claims.exp === 'number' ? claims.exp * 1000 : 0;
56
+ }
57
+ catch {
58
+ this.jwtExpiresAt = 0;
59
+ }
60
+ }
61
+ extractSession(data) {
62
+ if (!data || typeof data !== 'object') {
63
+ throw new Error('/auth/bot-session: response body is not an object');
64
+ }
65
+ const d = data;
66
+ if (typeof d.token !== 'string' || d.token.length === 0) {
67
+ throw new Error('/auth/bot-session: missing or empty `token`');
68
+ }
69
+ if (typeof d.userId !== 'number' || !Number.isInteger(d.userId) || d.userId < 1) {
70
+ throw new Error('/auth/bot-session: missing or invalid `userId`');
71
+ }
72
+ if (typeof d.username !== 'string' || d.username.length === 0) {
73
+ throw new Error('/auth/bot-session: missing or empty `username`');
74
+ }
75
+ if (typeof d.deviceId !== 'number' || !Number.isInteger(d.deviceId)) {
76
+ throw new Error('/auth/bot-session: missing or invalid `deviceId`');
77
+ }
78
+ return { token: d.token, userId: d.userId, username: d.username, deviceId: d.deviceId };
79
+ }
80
+ async doRefresh() {
81
+ const res = await axios.post(`${this.config.apiBaseUrl}/auth/bot-session`, { token: this.config.botToken, deviceName: 'bot-sdk', platform: 'bot' }, { timeout: 30_000 });
82
+ const session = this.extractSession(res.data);
83
+ this.jwt = session.token;
84
+ this.updateExpiryFromJwt(this.jwt);
85
+ this.config.onJwtRefreshed?.(this.jwt, this.jwtExpiresAt);
86
+ this.logger?.debug({ userId: session.userId, expiresAt: new Date(this.jwtExpiresAt).toISOString() }, '[http] minted bot-session JWT');
87
+ }
88
+ async initialMint() {
89
+ const res = await axios.post(`${this.config.apiBaseUrl}/auth/bot-session`, { token: this.config.botToken, deviceName: 'bot-sdk', platform: 'bot' }, { timeout: 30_000 });
90
+ const session = this.extractSession(res.data);
91
+ this.jwt = session.token;
92
+ this.updateExpiryFromJwt(this.jwt);
93
+ this.config.onJwtRefreshed?.(this.jwt, this.jwtExpiresAt);
94
+ this.logger?.info({ userId: session.userId, username: session.username }, '[http] bot-session established');
95
+ return session;
96
+ }
97
+ getJwt() {
98
+ return this.jwt;
99
+ }
100
+ needsProactiveRefresh(skewMs = 5 * 60 * 1000) {
101
+ if (!this.jwt || this.jwtExpiresAt === 0)
102
+ return false;
103
+ return Date.now() + skewMs >= this.jwtExpiresAt;
104
+ }
105
+ async get(url, cfg) {
106
+ return this.axios.get(url, cfg);
107
+ }
108
+ async post(url, body, cfg) {
109
+ return this.axios.post(url, body, cfg);
110
+ }
111
+ }
112
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Single long-lived WebSocket with exponential-backoff reconnect, an auth frame on every connect,
3
+ * and a send queue while disconnected
4
+ *
5
+ * Server contract:
6
+ * - client opens GET /ws and sends { type: 'auth', token, deviceId, locale } within 5s, server replies
7
+ * { type: 'ready' } or { type: 'error' } + close
8
+ * - after ready, either side sends arbitrary frames
9
+ * - server pings every 30s, client pongs, idle timeout 90s
10
+ * - on JWT revoke the server closes with 4001, SDK refreshes the JWT before reconnecting
11
+ *
12
+ * Send queue holds at most 1000 frames while disconnected and drains on the next ready, oldest dropped on overflow
13
+ */
14
+ import { EventEmitter } from 'node:events';
15
+ import type { SdkLogger } from '../types.js';
16
+ export interface WsClientConfig {
17
+ wsUrl: string;
18
+ deviceId: number;
19
+ getJwt: () => string | null;
20
+ /** Force a JWT refresh, called on code 4001 / auth errors */
21
+ refreshJwt: () => Promise<void>;
22
+ logger?: SdkLogger;
23
+ }
24
+ export interface IncomingFrame {
25
+ type: string;
26
+ [key: string]: unknown;
27
+ }
28
+ interface WsEvents {
29
+ frame: (frame: IncomingFrame) => void;
30
+ open: () => void;
31
+ close: (info: {
32
+ code: number;
33
+ reason: string;
34
+ willReconnect: boolean;
35
+ }) => void;
36
+ error: (err: Error) => void;
37
+ /** Fires once the server's `ready` lands. open alone isn't enough, the server can reject the auth frame */
38
+ ready: () => void;
39
+ }
40
+ export declare class WsClient extends EventEmitter {
41
+ private readonly config;
42
+ private socket?;
43
+ private sendQueue;
44
+ private connected;
45
+ private authed;
46
+ private shuttingDown;
47
+ private reconnectAttempts;
48
+ private reconnectTimer?;
49
+ private authTimer?;
50
+ constructor(config: WsClientConfig);
51
+ get isConnected(): boolean;
52
+ /** Open the socket. Resolves on the first ready */
53
+ start(): Promise<void>;
54
+ /** Clean close. Won't reconnect */
55
+ stop(): void;
56
+ /** Send a frame. If authed, dispatched directly, otherwise queued. Best-effort, no application-level ack */
57
+ send(frame: object): void;
58
+ private openSocket;
59
+ private scheduleReconnect;
60
+ on<K extends keyof WsEvents>(event: K, listener: WsEvents[K]): this;
61
+ off<K extends keyof WsEvents>(event: K, listener: WsEvents[K]): this;
62
+ emit<K extends keyof WsEvents>(event: K, ...args: Parameters<WsEvents[K]>): boolean;
63
+ }
64
+ export {};
65
+ //# sourceMappingURL=ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG5C,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAK,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAI,MAAM,MAAM,GAAG,IAAI,CAAA;IAC7B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,CAAC,EAAG,SAAS,CAAA;CACtB;AAGD,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACzB;AAED,UAAU,QAAQ;IACd,KAAK,EAAO,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC1C,IAAI,EAAQ,MAAM,IAAI,CAAA;IACtB,KAAK,EAAO,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACpF,KAAK,EAAO,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,2GAA2G;IAC3G,KAAK,EAAO,MAAM,IAAI,CAAA;CACzB;AASD,qBAAa,QAAS,SAAQ,YAAY;IAU1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IATnC,OAAO,CAAC,MAAM,CAAC,CAAkB;IACjC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,SAAS,CAAC,CAAqB;gBAEV,MAAM,EAAE,cAAc;IAEnD,IAAI,WAAW,IAAI,OAAO,CAAuB;IAEjD,mDAAmD;IAC7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB5B,mCAAmC;IACnC,IAAI,IAAI,IAAI;IAoBZ,4GAA4G;IAC5G,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IA8BzB,OAAO,CAAC,UAAU;IAyIlB,OAAO,CAAC,iBAAiB;IAuBhB,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAGnE,GAAG,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAGpE,IAAI,CAAC,CAAC,SAAS,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;CAG/F"}
@@ -0,0 +1,219 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import WebSocket from 'ws';
3
+ const MAX_QUEUE = 1000;
4
+ const RECONNECT_MIN_MS = 500;
5
+ const RECONNECT_MAX_MS = 30_000;
6
+ const AUTH_TIMEOUT_MS = 10_000;
7
+ export class WsClient extends EventEmitter {
8
+ config;
9
+ socket;
10
+ sendQueue = [];
11
+ connected = false;
12
+ authed = false;
13
+ shuttingDown = false;
14
+ reconnectAttempts = 0;
15
+ reconnectTimer;
16
+ authTimer;
17
+ constructor(config) {
18
+ super();
19
+ this.config = config;
20
+ }
21
+ get isConnected() { return this.authed; }
22
+ async start() {
23
+ if (this.connected || this.shuttingDown || this.socket)
24
+ return;
25
+ return new Promise((resolve, reject) => {
26
+ const onReady = () => {
27
+ this.off('ready', onReady);
28
+ this.off('error', onError);
29
+ resolve();
30
+ };
31
+ const onError = (err) => {
32
+ this.off('ready', onReady);
33
+ this.off('error', onError);
34
+ reject(err);
35
+ };
36
+ this.on('ready', onReady);
37
+ this.on('error', onError);
38
+ this.openSocket();
39
+ });
40
+ }
41
+ stop() {
42
+ this.shuttingDown = true;
43
+ if (this.reconnectTimer) {
44
+ clearTimeout(this.reconnectTimer);
45
+ this.reconnectTimer = undefined;
46
+ }
47
+ if (this.authTimer) {
48
+ clearTimeout(this.authTimer);
49
+ this.authTimer = undefined;
50
+ }
51
+ if (this.socket && this.socket.readyState <= WebSocket.OPEN) {
52
+ try {
53
+ this.socket.close(1000, 'sdk shutdown');
54
+ }
55
+ catch { }
56
+ }
57
+ this.socket = undefined;
58
+ this.connected = false;
59
+ this.authed = false;
60
+ this.sendQueue = [];
61
+ }
62
+ send(frame) {
63
+ let payload;
64
+ try {
65
+ payload = JSON.stringify(frame);
66
+ }
67
+ catch (err) {
68
+ this.config.logger?.warn({ err: err.message }, '[ws] send: frame not JSON-serializable, dropping');
69
+ return;
70
+ }
71
+ if (this.authed && this.socket?.readyState === WebSocket.OPEN) {
72
+ this.socket.send(payload);
73
+ return;
74
+ }
75
+ if (this.sendQueue.length >= MAX_QUEUE) {
76
+ const dropped = this.sendQueue.shift();
77
+ this.config.logger?.warn({ dropped: dropped?.slice(0, 80), queue: this.sendQueue.length }, '[ws] send queue overflow, dropping oldest frame');
78
+ }
79
+ this.sendQueue.push(payload);
80
+ }
81
+ openSocket() {
82
+ const url = this.config.wsUrl;
83
+ this.config.logger?.debug({ url }, '[ws] opening socket');
84
+ const socket = new WebSocket(url);
85
+ this.socket = socket;
86
+ socket.on('open', () => {
87
+ this.connected = true;
88
+ this.reconnectAttempts = 0;
89
+ this.config.logger?.debug({}, '[ws] socket open, sending auth frame');
90
+ const jwt = this.config.getJwt();
91
+ if (!jwt) {
92
+ socket.close(4001, 'no-jwt');
93
+ return;
94
+ }
95
+ try {
96
+ socket.send(JSON.stringify({
97
+ type: 'auth',
98
+ token: jwt,
99
+ deviceId: this.config.deviceId,
100
+ locale: 'en',
101
+ }));
102
+ }
103
+ catch (err) {
104
+ this.config.logger?.warn({ err: err.message }, '[ws] auth-frame send threw; falling through to reconnect');
105
+ try {
106
+ socket.close(4003, 'auth-send-failed');
107
+ }
108
+ catch { }
109
+ return;
110
+ }
111
+ this.authTimer = setTimeout(() => {
112
+ this.config.logger?.warn({}, '[ws] auth timeout, closing socket');
113
+ try {
114
+ socket.close(4002, 'auth-timeout');
115
+ }
116
+ catch { }
117
+ }, AUTH_TIMEOUT_MS);
118
+ this.emit('open');
119
+ });
120
+ socket.on('message', (data) => {
121
+ let parsed;
122
+ try {
123
+ parsed = JSON.parse(data.toString('utf8'));
124
+ }
125
+ catch (err) {
126
+ this.config.logger?.warn({ err: err.message }, '[ws] non-JSON frame, dropping');
127
+ return;
128
+ }
129
+ if (!parsed || typeof parsed !== 'object' || typeof parsed.type !== 'string') {
130
+ this.config.logger?.warn({ frame: parsed }, '[ws] frame missing type');
131
+ return;
132
+ }
133
+ const frame = parsed;
134
+ if (frame.type === 'ping') {
135
+ if (this.socket?.readyState === WebSocket.OPEN) {
136
+ try {
137
+ this.socket.send(JSON.stringify({ type: 'pong' }));
138
+ }
139
+ catch (err) {
140
+ this.config.logger?.warn({ err: err.message }, '[ws] pong send failed; close handler will reconnect');
141
+ }
142
+ }
143
+ return;
144
+ }
145
+ if (!this.authed && frame.type === 'ready') {
146
+ if (this.authTimer) {
147
+ clearTimeout(this.authTimer);
148
+ this.authTimer = undefined;
149
+ }
150
+ this.authed = true;
151
+ this.config.logger?.info({}, '[ws] auth complete, draining send queue');
152
+ while (this.sendQueue.length > 0 && this.socket?.readyState === WebSocket.OPEN) {
153
+ const payload = this.sendQueue.shift();
154
+ this.socket.send(payload);
155
+ }
156
+ this.emit('ready');
157
+ return;
158
+ }
159
+ if (!this.authed && frame.type === 'error') {
160
+ this.config.logger?.warn({ frame }, '[ws] auth-frame error from server');
161
+ }
162
+ this.emit('frame', frame);
163
+ });
164
+ socket.on('close', (code, reasonBuf) => {
165
+ const reason = reasonBuf?.toString('utf8') ?? '';
166
+ const wasAuthed = this.authed;
167
+ this.connected = false;
168
+ this.authed = false;
169
+ this.socket = undefined;
170
+ if (this.authTimer) {
171
+ clearTimeout(this.authTimer);
172
+ this.authTimer = undefined;
173
+ }
174
+ const willReconnect = !this.shuttingDown;
175
+ this.config.logger?.info({ code, reason, willReconnect, wasAuthed }, '[ws] socket closed');
176
+ this.emit('close', { code, reason, willReconnect });
177
+ if (!willReconnect)
178
+ return;
179
+ if (code === 4001) {
180
+ this.config.logger?.info({}, '[ws] code 4001 - refreshing JWT before reconnect');
181
+ this.config.refreshJwt()
182
+ .catch(err => {
183
+ this.config.logger?.warn({ err: err.message }, '[ws] JWT refresh failed; will retry via reconnect');
184
+ })
185
+ .finally(() => {
186
+ this.scheduleReconnect();
187
+ });
188
+ return;
189
+ }
190
+ this.scheduleReconnect();
191
+ });
192
+ socket.on('error', (err) => {
193
+ this.config.logger?.warn({ err: err.message }, '[ws] socket error');
194
+ this.emit('error', err);
195
+ });
196
+ }
197
+ scheduleReconnect() {
198
+ if (this.shuttingDown || this.reconnectTimer)
199
+ return;
200
+ const base = Math.min(RECONNECT_MAX_MS, RECONNECT_MIN_MS * Math.pow(2, this.reconnectAttempts));
201
+ const delay = Math.floor(base / 2 + Math.random() * (base / 2));
202
+ this.reconnectAttempts++;
203
+ this.config.logger?.debug({ delayMs: delay, attempt: this.reconnectAttempts }, '[ws] scheduling reconnect');
204
+ this.reconnectTimer = setTimeout(() => {
205
+ this.reconnectTimer = undefined;
206
+ this.openSocket();
207
+ }, delay);
208
+ }
209
+ on(event, listener) {
210
+ return super.on(event, listener);
211
+ }
212
+ off(event, listener) {
213
+ return super.off(event, listener);
214
+ }
215
+ emit(event, ...args) {
216
+ return super.emit(event, ...args);
217
+ }
218
+ }
219
+ //# sourceMappingURL=ws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"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"}