@mrdoge/node 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 +201 -0
- package/README.md +280 -0
- package/dist/index.d.mts +417 -0
- package/dist/index.d.ts +417 -0
- package/dist/index.js +1000 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +949 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1000 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
AbortError: () => AbortError,
|
|
34
|
+
ConnectionError: () => ConnectionError,
|
|
35
|
+
ConnectionLimitError: () => ConnectionLimitError,
|
|
36
|
+
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
37
|
+
DisconnectedError: () => DisconnectedError,
|
|
38
|
+
ForbiddenError: () => ForbiddenError,
|
|
39
|
+
InternalError: () => InternalError,
|
|
40
|
+
MrDoge: () => MrDoge,
|
|
41
|
+
MrDogeError: () => MrDogeError,
|
|
42
|
+
NotFoundError: () => NotFoundError,
|
|
43
|
+
ProtocolError: () => ProtocolError,
|
|
44
|
+
RateLimitError: () => RateLimitError,
|
|
45
|
+
Subscription: () => Subscription,
|
|
46
|
+
SubscriptionLimitError: () => SubscriptionLimitError,
|
|
47
|
+
TimeoutError: () => TimeoutError,
|
|
48
|
+
UnauthorizedError: () => UnauthorizedError,
|
|
49
|
+
UnavailableError: () => UnavailableError,
|
|
50
|
+
ValidationError: () => ValidationError
|
|
51
|
+
});
|
|
52
|
+
module.exports = __toCommonJS(index_exports);
|
|
53
|
+
|
|
54
|
+
// src/client.ts
|
|
55
|
+
var import_http = require("@mrdoge/http");
|
|
56
|
+
|
|
57
|
+
// src/connection.ts
|
|
58
|
+
var import_ws = __toESM(require("ws"));
|
|
59
|
+
var import_protocol = require("@mrdoge/protocol");
|
|
60
|
+
|
|
61
|
+
// src/errors.ts
|
|
62
|
+
var MrDogeError = class extends Error {
|
|
63
|
+
code;
|
|
64
|
+
data;
|
|
65
|
+
constructor(code, message, data) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = this.constructor.name;
|
|
68
|
+
this.code = code;
|
|
69
|
+
this.data = data;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var UnauthorizedError = class extends MrDogeError {
|
|
73
|
+
constructor(message, data) {
|
|
74
|
+
super("unauthorized", message, data);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var ForbiddenError = class extends MrDogeError {
|
|
78
|
+
constructor(message, data) {
|
|
79
|
+
super("forbidden", message, data);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var NotFoundError = class extends MrDogeError {
|
|
83
|
+
constructor(message, data) {
|
|
84
|
+
super("not_found", message, data);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var ValidationError = class extends MrDogeError {
|
|
88
|
+
constructor(message, data) {
|
|
89
|
+
super("invalid_params", message, data);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
var RateLimitError = class extends MrDogeError {
|
|
93
|
+
retryAfterMs;
|
|
94
|
+
limit;
|
|
95
|
+
remaining;
|
|
96
|
+
resetAt;
|
|
97
|
+
constructor(message, data) {
|
|
98
|
+
super("rate_limited", message, data);
|
|
99
|
+
const d = data ?? {};
|
|
100
|
+
this.retryAfterMs = d.retryAfterMs ?? 0;
|
|
101
|
+
this.limit = d.limit;
|
|
102
|
+
this.remaining = d.remaining;
|
|
103
|
+
this.resetAt = d.resetAt ? new Date(d.resetAt) : void 0;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var SubscriptionLimitError = class extends MrDogeError {
|
|
107
|
+
constructor(message, data) {
|
|
108
|
+
super("subscription_limit_exceeded", message, data);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var ConnectionLimitError = class extends MrDogeError {
|
|
112
|
+
current;
|
|
113
|
+
max;
|
|
114
|
+
constructor(message, data) {
|
|
115
|
+
super("connection_limit_exceeded", message, data);
|
|
116
|
+
const d = data ?? {};
|
|
117
|
+
this.current = d.current;
|
|
118
|
+
this.max = d.max;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var UnavailableError = class extends MrDogeError {
|
|
122
|
+
constructor(message, data) {
|
|
123
|
+
super("unavailable", message, data);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
var InternalError = class extends MrDogeError {
|
|
127
|
+
constructor(message, data) {
|
|
128
|
+
super("internal_error", message, data);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var ProtocolError = class extends MrDogeError {
|
|
132
|
+
constructor(message, data) {
|
|
133
|
+
super("protocol_error", message, data);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var ConnectionError = class extends MrDogeError {
|
|
137
|
+
constructor(message, data) {
|
|
138
|
+
super("connection_error", message, data);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var DisconnectedError = class extends MrDogeError {
|
|
142
|
+
constructor(message = "Connection dropped before response", data) {
|
|
143
|
+
super("disconnected", message, data);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var TimeoutError = class extends MrDogeError {
|
|
147
|
+
constructor(message, data) {
|
|
148
|
+
super("timeout", message, data);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
var AbortError = class extends MrDogeError {
|
|
152
|
+
constructor(message = "Request aborted") {
|
|
153
|
+
super("aborted", message);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var CODE_MAP = {
|
|
157
|
+
invalid_request: ProtocolError,
|
|
158
|
+
invalid_params: ValidationError,
|
|
159
|
+
method_not_found: ProtocolError,
|
|
160
|
+
unauthorized: UnauthorizedError,
|
|
161
|
+
forbidden: ForbiddenError,
|
|
162
|
+
not_found: NotFoundError,
|
|
163
|
+
rate_limited: RateLimitError,
|
|
164
|
+
subscription_limit_exceeded: SubscriptionLimitError,
|
|
165
|
+
connection_limit_exceeded: ConnectionLimitError,
|
|
166
|
+
unavailable: UnavailableError,
|
|
167
|
+
internal_error: InternalError,
|
|
168
|
+
protocol_error: ProtocolError
|
|
169
|
+
};
|
|
170
|
+
function rpcErrorToTyped(err) {
|
|
171
|
+
const Ctor = CODE_MAP[err.code];
|
|
172
|
+
if (!Ctor) return new MrDogeError("unknown", err.message, err.data);
|
|
173
|
+
return new Ctor(err.message, err.data);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/internal/emitter.ts
|
|
177
|
+
var Emitter = class {
|
|
178
|
+
listeners = /* @__PURE__ */ new Map();
|
|
179
|
+
on(event, fn) {
|
|
180
|
+
let set = this.listeners.get(event);
|
|
181
|
+
if (!set) {
|
|
182
|
+
set = /* @__PURE__ */ new Set();
|
|
183
|
+
this.listeners.set(event, set);
|
|
184
|
+
}
|
|
185
|
+
set.add(fn);
|
|
186
|
+
return () => set.delete(fn);
|
|
187
|
+
}
|
|
188
|
+
off(event, fn) {
|
|
189
|
+
this.listeners.get(event)?.delete(fn);
|
|
190
|
+
}
|
|
191
|
+
emit(event, payload) {
|
|
192
|
+
const set = this.listeners.get(event);
|
|
193
|
+
if (!set || set.size === 0) return;
|
|
194
|
+
for (const fn of [...set]) {
|
|
195
|
+
try {
|
|
196
|
+
fn(payload);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
queueMicrotask(() => {
|
|
199
|
+
throw err;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
clear() {
|
|
205
|
+
this.listeners.clear();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// src/internal/backoff.ts
|
|
210
|
+
var DEFAULT_BACKOFF = {
|
|
211
|
+
minMs: 1e3,
|
|
212
|
+
maxMs: 3e4,
|
|
213
|
+
jitter: 0.2
|
|
214
|
+
};
|
|
215
|
+
function nextDelay(attempt, cfg = DEFAULT_BACKOFF) {
|
|
216
|
+
const exp = Math.min(cfg.maxMs, cfg.minMs * 2 ** (attempt - 1));
|
|
217
|
+
const jitter = exp * cfg.jitter * (Math.random() * 2 - 1);
|
|
218
|
+
return Math.max(0, Math.round(exp + jitter));
|
|
219
|
+
}
|
|
220
|
+
function sleep(ms, signal) {
|
|
221
|
+
return new Promise((resolve, reject) => {
|
|
222
|
+
if (signal?.aborted) {
|
|
223
|
+
reject(new Error("aborted"));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const t = setTimeout(resolve, ms);
|
|
227
|
+
signal?.addEventListener("abort", () => {
|
|
228
|
+
clearTimeout(t);
|
|
229
|
+
reject(new Error("aborted"));
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/connection.ts
|
|
235
|
+
var TERMINAL_CLOSE_CODES = /* @__PURE__ */ new Set([4001, 4002, 4003, 4029]);
|
|
236
|
+
var DEFAULT_CONFIG = {
|
|
237
|
+
requestTimeoutMs: 1e4,
|
|
238
|
+
maxReconnectAttempts: Infinity,
|
|
239
|
+
reconnectBackoff: DEFAULT_BACKOFF,
|
|
240
|
+
compression: true,
|
|
241
|
+
authTimeoutMs: 1e4
|
|
242
|
+
};
|
|
243
|
+
var Connection = class {
|
|
244
|
+
emitter = new Emitter();
|
|
245
|
+
config;
|
|
246
|
+
ws = null;
|
|
247
|
+
nextRequestId = 1;
|
|
248
|
+
pending = /* @__PURE__ */ new Map();
|
|
249
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
250
|
+
connectingPromise = null;
|
|
251
|
+
welcome = null;
|
|
252
|
+
closed = false;
|
|
253
|
+
reconnectAttempt = 0;
|
|
254
|
+
reconnectAbort = null;
|
|
255
|
+
constructor(config) {
|
|
256
|
+
this.config = config;
|
|
257
|
+
}
|
|
258
|
+
on = this.emitter.on.bind(this.emitter);
|
|
259
|
+
off = this.emitter.off.bind(this.emitter);
|
|
260
|
+
get isConnected() {
|
|
261
|
+
return this.ws?.readyState === import_ws.default.OPEN && this.welcome !== null;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Idempotent. Returns the welcome payload once connected + authed.
|
|
265
|
+
*/
|
|
266
|
+
async connect() {
|
|
267
|
+
if (this.closed) throw new ConnectionError("Connection is closed");
|
|
268
|
+
if (this.welcome && this.ws?.readyState === import_ws.default.OPEN) return this.welcome;
|
|
269
|
+
if (this.connectingPromise) return this.connectingPromise;
|
|
270
|
+
this.connectingPromise = this.openAndAuth().finally(() => {
|
|
271
|
+
this.connectingPromise = null;
|
|
272
|
+
});
|
|
273
|
+
return this.connectingPromise;
|
|
274
|
+
}
|
|
275
|
+
async call(method, params, options) {
|
|
276
|
+
await this.connect();
|
|
277
|
+
return this.send(method, params, options);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Registers a subscription with the connection. The connection sends the
|
|
281
|
+
* subscribe call, stores the registration for reconnect, and routes incoming
|
|
282
|
+
* push events to the handler.
|
|
283
|
+
*/
|
|
284
|
+
async registerSubscription(method, params, handlers, options) {
|
|
285
|
+
await this.connect();
|
|
286
|
+
const result = await this.send(method, params, options);
|
|
287
|
+
const registration = {
|
|
288
|
+
subId: result.sub,
|
|
289
|
+
method,
|
|
290
|
+
params,
|
|
291
|
+
onEvent: handlers.onEvent,
|
|
292
|
+
onClosed: handlers.onClosed,
|
|
293
|
+
onSnapshot: handlers.onSnapshot
|
|
294
|
+
};
|
|
295
|
+
this.subscriptions.set(result.sub, registration);
|
|
296
|
+
return { subId: result.sub, snapshot: result.snapshot };
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Cancels a subscription server-side and removes the registration locally.
|
|
300
|
+
*/
|
|
301
|
+
async cancelSubscription(subId) {
|
|
302
|
+
const reg = this.subscriptions.get(subId);
|
|
303
|
+
if (!reg) return;
|
|
304
|
+
this.subscriptions.delete(subId);
|
|
305
|
+
if (this.ws?.readyState === import_ws.default.OPEN) {
|
|
306
|
+
try {
|
|
307
|
+
await this.send("subscription.cancel", { sub: subId });
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async close() {
|
|
313
|
+
this.closed = true;
|
|
314
|
+
this.reconnectAbort?.abort();
|
|
315
|
+
this.reconnectAbort = null;
|
|
316
|
+
for (const [, p] of this.pending) {
|
|
317
|
+
clearTimeout(p.timer);
|
|
318
|
+
p.reject(new DisconnectedError("Connection closed by client"));
|
|
319
|
+
}
|
|
320
|
+
this.pending.clear();
|
|
321
|
+
this.subscriptions.clear();
|
|
322
|
+
if (this.ws && this.ws.readyState <= import_ws.default.OPEN) {
|
|
323
|
+
this.ws.close(1e3, "client_close");
|
|
324
|
+
}
|
|
325
|
+
this.ws = null;
|
|
326
|
+
this.welcome = null;
|
|
327
|
+
}
|
|
328
|
+
// -------------------------------------------------------------------------
|
|
329
|
+
// Internals
|
|
330
|
+
// -------------------------------------------------------------------------
|
|
331
|
+
async openAndAuth() {
|
|
332
|
+
const ws = new import_ws.default(this.config.baseUrl, [import_protocol.SUBPROTOCOL], {
|
|
333
|
+
perMessageDeflate: this.config.compression ? { threshold: 1024 } : false,
|
|
334
|
+
handshakeTimeout: 15e3
|
|
335
|
+
});
|
|
336
|
+
this.ws = ws;
|
|
337
|
+
this.welcome = null;
|
|
338
|
+
await new Promise((resolve, reject) => {
|
|
339
|
+
const onOpen = () => {
|
|
340
|
+
cleanup();
|
|
341
|
+
resolve();
|
|
342
|
+
};
|
|
343
|
+
const onError = (err) => {
|
|
344
|
+
cleanup();
|
|
345
|
+
reject(new ConnectionError(`Failed to open WebSocket: ${err.message}`));
|
|
346
|
+
};
|
|
347
|
+
const onClose = (code, reason) => {
|
|
348
|
+
cleanup();
|
|
349
|
+
reject(new ConnectionError(`WebSocket closed before open (${code}): ${reason.toString()}`));
|
|
350
|
+
};
|
|
351
|
+
const cleanup = () => {
|
|
352
|
+
ws.off("open", onOpen);
|
|
353
|
+
ws.off("error", onError);
|
|
354
|
+
ws.off("close", onClose);
|
|
355
|
+
};
|
|
356
|
+
ws.once("open", onOpen);
|
|
357
|
+
ws.once("error", onError);
|
|
358
|
+
ws.once("close", onClose);
|
|
359
|
+
});
|
|
360
|
+
ws.on("message", (data) => this.handleMessage(data));
|
|
361
|
+
ws.on("close", (code, reason) => this.handleClose(code, reason.toString()));
|
|
362
|
+
ws.on("error", (err) => this.handleSocketError(err));
|
|
363
|
+
const welcome = await this.performAuth();
|
|
364
|
+
this.welcome = welcome;
|
|
365
|
+
this.reconnectAttempt = 0;
|
|
366
|
+
this.emitter.emit("connected", { welcome });
|
|
367
|
+
if (this.subscriptions.size > 0) {
|
|
368
|
+
await this.resubscribeAll();
|
|
369
|
+
}
|
|
370
|
+
return welcome;
|
|
371
|
+
}
|
|
372
|
+
async performAuth() {
|
|
373
|
+
const welcomePromise = new Promise((resolve, reject) => {
|
|
374
|
+
const timer = setTimeout(() => {
|
|
375
|
+
reject(new TimeoutError("Auth timed out waiting for welcome"));
|
|
376
|
+
}, this.config.authTimeoutMs);
|
|
377
|
+
this.pendingWelcome = {
|
|
378
|
+
resolve,
|
|
379
|
+
reject,
|
|
380
|
+
timer
|
|
381
|
+
};
|
|
382
|
+
});
|
|
383
|
+
const authAck = this.send("auth", { apiKey: this.config.apiKey }).catch(
|
|
384
|
+
(err) => {
|
|
385
|
+
if (err instanceof MrDogeError) throw err;
|
|
386
|
+
throw new UnauthorizedError(`Authentication failed: ${err.message}`);
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
await authAck;
|
|
390
|
+
return welcomePromise;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Set during `performAuth` so we can resolve when the `welcome` notification arrives.
|
|
394
|
+
*/
|
|
395
|
+
pendingWelcome = null;
|
|
396
|
+
send(method, params, options) {
|
|
397
|
+
if (options?.signal?.aborted) {
|
|
398
|
+
return Promise.reject(new AbortError());
|
|
399
|
+
}
|
|
400
|
+
const ws = this.ws;
|
|
401
|
+
if (!ws || ws.readyState !== import_ws.default.OPEN) {
|
|
402
|
+
return Promise.reject(new DisconnectedError("Socket not open"));
|
|
403
|
+
}
|
|
404
|
+
const id = String(this.nextRequestId++);
|
|
405
|
+
const frame = {
|
|
406
|
+
jsonrpc: "2.0",
|
|
407
|
+
id,
|
|
408
|
+
method,
|
|
409
|
+
params
|
|
410
|
+
};
|
|
411
|
+
return new Promise((resolve, reject) => {
|
|
412
|
+
const onAbort = () => {
|
|
413
|
+
this.pending.delete(id);
|
|
414
|
+
clearTimeout(timer);
|
|
415
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
416
|
+
reject(new AbortError());
|
|
417
|
+
};
|
|
418
|
+
const detachSignal = () => {
|
|
419
|
+
options?.signal?.removeEventListener("abort", onAbort);
|
|
420
|
+
};
|
|
421
|
+
const wrappedResolve = (val) => {
|
|
422
|
+
detachSignal();
|
|
423
|
+
resolve(val);
|
|
424
|
+
};
|
|
425
|
+
const wrappedReject = (err) => {
|
|
426
|
+
detachSignal();
|
|
427
|
+
reject(err);
|
|
428
|
+
};
|
|
429
|
+
const timer = setTimeout(() => {
|
|
430
|
+
this.pending.delete(id);
|
|
431
|
+
detachSignal();
|
|
432
|
+
reject(new TimeoutError(`Request "${method}" timed out after ${this.config.requestTimeoutMs}ms`));
|
|
433
|
+
}, this.config.requestTimeoutMs);
|
|
434
|
+
this.pending.set(id, { resolve: wrappedResolve, reject: wrappedReject, timer });
|
|
435
|
+
options?.signal?.addEventListener("abort", onAbort);
|
|
436
|
+
try {
|
|
437
|
+
ws.send(JSON.stringify(frame));
|
|
438
|
+
} catch (err) {
|
|
439
|
+
this.pending.delete(id);
|
|
440
|
+
clearTimeout(timer);
|
|
441
|
+
detachSignal();
|
|
442
|
+
reject(new ConnectionError(`Failed to send frame: ${err.message}`));
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
handleMessage(raw) {
|
|
447
|
+
let text;
|
|
448
|
+
if (typeof raw === "string") text = raw;
|
|
449
|
+
else if (Buffer.isBuffer(raw)) text = raw.toString("utf8");
|
|
450
|
+
else if (raw instanceof ArrayBuffer) text = Buffer.from(raw).toString("utf8");
|
|
451
|
+
else text = Buffer.concat(raw).toString("utf8");
|
|
452
|
+
let frame;
|
|
453
|
+
try {
|
|
454
|
+
frame = JSON.parse(text);
|
|
455
|
+
} catch {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (frame.jsonrpc !== "2.0") return;
|
|
459
|
+
if (typeof frame.id === "string") {
|
|
460
|
+
const p = this.pending.get(frame.id);
|
|
461
|
+
if (!p) return;
|
|
462
|
+
this.pending.delete(frame.id);
|
|
463
|
+
clearTimeout(p.timer);
|
|
464
|
+
if (frame.error) {
|
|
465
|
+
p.reject(rpcErrorToTyped(frame.error));
|
|
466
|
+
} else {
|
|
467
|
+
p.resolve(frame.result);
|
|
468
|
+
}
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (typeof frame.method === "string") {
|
|
472
|
+
this.handleNotification(frame.method, frame.params);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
handleNotification(method, params) {
|
|
476
|
+
if (method === "welcome") {
|
|
477
|
+
const pending = this.pendingWelcome;
|
|
478
|
+
this.pendingWelcome = null;
|
|
479
|
+
if (pending) {
|
|
480
|
+
clearTimeout(pending.timer);
|
|
481
|
+
pending.resolve(params);
|
|
482
|
+
}
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (method === "subscription.event") {
|
|
486
|
+
const p = params;
|
|
487
|
+
const reg = this.subscriptions.get(p.sub);
|
|
488
|
+
reg?.onEvent(p);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (method === "subscription.closed") {
|
|
492
|
+
const p = params;
|
|
493
|
+
const reg = this.subscriptions.get(p.sub);
|
|
494
|
+
if (reg) {
|
|
495
|
+
this.subscriptions.delete(p.sub);
|
|
496
|
+
reg.onClosed(p);
|
|
497
|
+
}
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
handleClose(code, reason) {
|
|
502
|
+
const wasConnected = this.welcome !== null;
|
|
503
|
+
this.welcome = null;
|
|
504
|
+
this.ws = null;
|
|
505
|
+
for (const [, p] of this.pending) {
|
|
506
|
+
clearTimeout(p.timer);
|
|
507
|
+
p.reject(new DisconnectedError(`Connection closed (${code}): ${reason}`));
|
|
508
|
+
}
|
|
509
|
+
this.pending.clear();
|
|
510
|
+
if (this.pendingWelcome) {
|
|
511
|
+
clearTimeout(this.pendingWelcome.timer);
|
|
512
|
+
this.pendingWelcome.reject(new DisconnectedError(`Connection closed during auth (${code})`));
|
|
513
|
+
this.pendingWelcome = null;
|
|
514
|
+
}
|
|
515
|
+
if (this.closed) return;
|
|
516
|
+
this.emitter.emit("disconnected", { code, reason });
|
|
517
|
+
if (TERMINAL_CLOSE_CODES.has(code)) {
|
|
518
|
+
this.closed = true;
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
if (wasConnected || this.subscriptions.size > 0) {
|
|
522
|
+
this.scheduleReconnect();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
handleSocketError(_err) {
|
|
526
|
+
}
|
|
527
|
+
async scheduleReconnect() {
|
|
528
|
+
if (this.closed) return;
|
|
529
|
+
if (this.reconnectAbort) return;
|
|
530
|
+
this.reconnectAbort = new AbortController();
|
|
531
|
+
const signal = this.reconnectAbort.signal;
|
|
532
|
+
while (!this.closed && this.reconnectAttempt < this.config.maxReconnectAttempts) {
|
|
533
|
+
this.reconnectAttempt += 1;
|
|
534
|
+
const delayMs = nextDelay(this.reconnectAttempt, this.config.reconnectBackoff);
|
|
535
|
+
this.emitter.emit("reconnecting", { attempt: this.reconnectAttempt, delayMs });
|
|
536
|
+
try {
|
|
537
|
+
await sleep(delayMs, signal);
|
|
538
|
+
} catch {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (this.closed) return;
|
|
542
|
+
try {
|
|
543
|
+
await this.openAndAuth();
|
|
544
|
+
this.reconnectAbort = null;
|
|
545
|
+
return;
|
|
546
|
+
} catch (err) {
|
|
547
|
+
if (err instanceof UnauthorizedError) {
|
|
548
|
+
this.closed = true;
|
|
549
|
+
this.reconnectAbort = null;
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
this.reconnectAbort = null;
|
|
555
|
+
}
|
|
556
|
+
async resubscribeAll() {
|
|
557
|
+
const olds = Array.from(this.subscriptions.values());
|
|
558
|
+
this.subscriptions.clear();
|
|
559
|
+
for (const old of olds) {
|
|
560
|
+
try {
|
|
561
|
+
const result = await this.send(old.method, old.params);
|
|
562
|
+
old.subId = result.sub;
|
|
563
|
+
this.subscriptions.set(result.sub, old);
|
|
564
|
+
old.onSnapshot(result.sub, result.snapshot);
|
|
565
|
+
} catch (err) {
|
|
566
|
+
old.onClosed({
|
|
567
|
+
sub: old.subId,
|
|
568
|
+
reason: "internal_error",
|
|
569
|
+
message: err instanceof Error ? `Resubscribe failed: ${err.message}` : "Resubscribe failed"
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// src/resources/regions.ts
|
|
577
|
+
var Regions = class {
|
|
578
|
+
constructor(conn, defaults) {
|
|
579
|
+
this.conn = conn;
|
|
580
|
+
this.defaults = defaults;
|
|
581
|
+
}
|
|
582
|
+
conn;
|
|
583
|
+
defaults;
|
|
584
|
+
list(params = {}, options) {
|
|
585
|
+
return this.conn.call(
|
|
586
|
+
"regions.list",
|
|
587
|
+
{ locale: this.defaults.locale, ...params },
|
|
588
|
+
options
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// src/resources/competitions.ts
|
|
594
|
+
var Competitions = class {
|
|
595
|
+
constructor(conn, defaults) {
|
|
596
|
+
this.conn = conn;
|
|
597
|
+
this.defaults = defaults;
|
|
598
|
+
}
|
|
599
|
+
conn;
|
|
600
|
+
defaults;
|
|
601
|
+
list(params = {}, options) {
|
|
602
|
+
return this.conn.call(
|
|
603
|
+
"competitions.list",
|
|
604
|
+
{ locale: this.defaults.locale, ...params },
|
|
605
|
+
options
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// src/resources/teams.ts
|
|
611
|
+
var Teams = class {
|
|
612
|
+
constructor(conn, defaults) {
|
|
613
|
+
this.conn = conn;
|
|
614
|
+
this.defaults = defaults;
|
|
615
|
+
}
|
|
616
|
+
conn;
|
|
617
|
+
defaults;
|
|
618
|
+
list(params = {}, options) {
|
|
619
|
+
return this.conn.call(
|
|
620
|
+
"teams.list",
|
|
621
|
+
{ locale: this.defaults.locale, ...params },
|
|
622
|
+
options
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
get(params, options) {
|
|
626
|
+
return this.conn.call(
|
|
627
|
+
"teams.get",
|
|
628
|
+
{ locale: this.defaults.locale, ...params },
|
|
629
|
+
options
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
form(params, options) {
|
|
633
|
+
return this.conn.call(
|
|
634
|
+
"teams.form",
|
|
635
|
+
{ locale: this.defaults.locale, ...params },
|
|
636
|
+
options
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
// src/subscription.ts
|
|
642
|
+
var PENDING_SUB_ID = "__pending_ws__";
|
|
643
|
+
var Subscription = class {
|
|
644
|
+
emitter = new Emitter();
|
|
645
|
+
connection;
|
|
646
|
+
internalSubId;
|
|
647
|
+
currentSnapshot;
|
|
648
|
+
cancelled = false;
|
|
649
|
+
/**
|
|
650
|
+
* True when `cancel()` was called before the WS subscribe arrived (subId
|
|
651
|
+
* still pending). Once WS resolves, `_deliverSnapshot` issues the
|
|
652
|
+
* server-side cancel so we don't leak a registered subscription.
|
|
653
|
+
*/
|
|
654
|
+
pendingCancel = false;
|
|
655
|
+
/** @internal — constructed by the SDK, not by user code. */
|
|
656
|
+
constructor(connection, subId, initialSnapshot) {
|
|
657
|
+
this.connection = connection;
|
|
658
|
+
this.internalSubId = subId;
|
|
659
|
+
this.currentSnapshot = initialSnapshot;
|
|
660
|
+
}
|
|
661
|
+
/** The latest snapshot the server has emitted (initial, or post-reconnect). */
|
|
662
|
+
get snapshot() {
|
|
663
|
+
return this.currentSnapshot;
|
|
664
|
+
}
|
|
665
|
+
/** Current server-issued subscription id. Changes on reconnect. */
|
|
666
|
+
get id() {
|
|
667
|
+
return this.internalSubId;
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Listen for a push event from this subscription. Returns an unsubscribe
|
|
671
|
+
* function that removes only this listener.
|
|
672
|
+
*
|
|
673
|
+
* In addition to protocol push events, two synthetic events fire:
|
|
674
|
+
* - `snapshot` — when a reconnect produced a fresh snapshot
|
|
675
|
+
* - `closed` — when the server terminates the subscription (or cancel)
|
|
676
|
+
*/
|
|
677
|
+
on(event, fn) {
|
|
678
|
+
return this.emitter.on(event, fn);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Cancel the subscription server-side. Idempotent — calling twice is safe.
|
|
682
|
+
*/
|
|
683
|
+
async cancel() {
|
|
684
|
+
if (this.cancelled) return;
|
|
685
|
+
this.cancelled = true;
|
|
686
|
+
if (this.internalSubId === PENDING_SUB_ID) {
|
|
687
|
+
this.pendingCancel = true;
|
|
688
|
+
this.emitter.clear();
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
await this.connection.cancelSubscription(this.internalSubId);
|
|
692
|
+
this.emitter.clear();
|
|
693
|
+
}
|
|
694
|
+
// ---------------------------------------------------------------------
|
|
695
|
+
// Internal — invoked by Connection's routing layer.
|
|
696
|
+
// ---------------------------------------------------------------------
|
|
697
|
+
/** @internal */
|
|
698
|
+
_deliverEvent(params) {
|
|
699
|
+
if (this.cancelled) return;
|
|
700
|
+
this.emitter.emit(
|
|
701
|
+
params.event,
|
|
702
|
+
params.data
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
/** @internal */
|
|
706
|
+
_deliverSnapshot(newSubId, snapshot) {
|
|
707
|
+
this.internalSubId = newSubId;
|
|
708
|
+
if (this.pendingCancel) {
|
|
709
|
+
this.pendingCancel = false;
|
|
710
|
+
this.connection.cancelSubscription(newSubId).catch(() => void 0);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (this.cancelled) return;
|
|
714
|
+
this.currentSnapshot = snapshot;
|
|
715
|
+
this.emitter.emit("snapshot", snapshot);
|
|
716
|
+
}
|
|
717
|
+
/** @internal */
|
|
718
|
+
_deliverClosed(reason, message) {
|
|
719
|
+
if (this.cancelled) return;
|
|
720
|
+
this.cancelled = true;
|
|
721
|
+
this.emitter.emit(
|
|
722
|
+
"closed",
|
|
723
|
+
{ reason, message }
|
|
724
|
+
);
|
|
725
|
+
this.emitter.clear();
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// src/resources/matches.ts
|
|
730
|
+
var Matches = class {
|
|
731
|
+
constructor(conn, defaults, http) {
|
|
732
|
+
this.conn = conn;
|
|
733
|
+
this.defaults = defaults;
|
|
734
|
+
this.http = http;
|
|
735
|
+
}
|
|
736
|
+
conn;
|
|
737
|
+
defaults;
|
|
738
|
+
http;
|
|
739
|
+
list(params = {}, options) {
|
|
740
|
+
return this.conn.call(
|
|
741
|
+
"matches.list",
|
|
742
|
+
{
|
|
743
|
+
locale: this.defaults.locale,
|
|
744
|
+
timezone: this.defaults.timezone,
|
|
745
|
+
...params
|
|
746
|
+
},
|
|
747
|
+
options
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
get(params, options) {
|
|
751
|
+
return this.conn.call(
|
|
752
|
+
"matches.get",
|
|
753
|
+
{ locale: this.defaults.locale, ...params },
|
|
754
|
+
options
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
trending(params = {}, options) {
|
|
758
|
+
return this.conn.call(
|
|
759
|
+
"matches.trending",
|
|
760
|
+
{
|
|
761
|
+
locale: this.defaults.locale,
|
|
762
|
+
timezone: this.defaults.timezone,
|
|
763
|
+
...params
|
|
764
|
+
},
|
|
765
|
+
options
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
search(params, options) {
|
|
769
|
+
return this.conn.call(
|
|
770
|
+
"matches.search",
|
|
771
|
+
{ locale: this.defaults.locale, ...params },
|
|
772
|
+
options
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
async subscribeLive(params = {}, options) {
|
|
776
|
+
const merged = { locale: this.defaults.locale, ...params };
|
|
777
|
+
let handle;
|
|
778
|
+
const wsPromise = this.conn.registerSubscription(
|
|
779
|
+
"matches.subscribeLive",
|
|
780
|
+
merged,
|
|
781
|
+
{
|
|
782
|
+
onEvent: (event) => handle?._deliverEvent(event),
|
|
783
|
+
onClosed: (p) => handle?._deliverClosed(p.reason, p.message),
|
|
784
|
+
onSnapshot: (newSubId, newSnap) => handle?._deliverSnapshot(newSubId, newSnap)
|
|
785
|
+
},
|
|
786
|
+
options
|
|
787
|
+
);
|
|
788
|
+
const httpPromise = this.http.call(
|
|
789
|
+
"matches.getLive",
|
|
790
|
+
merged,
|
|
791
|
+
options
|
|
792
|
+
).then((snapshot) => ({ kind: "http", snapshot }));
|
|
793
|
+
const wsRace = wsPromise.then((r) => ({
|
|
794
|
+
kind: "ws",
|
|
795
|
+
subId: r.subId,
|
|
796
|
+
snapshot: r.snapshot
|
|
797
|
+
}));
|
|
798
|
+
let winner;
|
|
799
|
+
try {
|
|
800
|
+
winner = await Promise.race([httpPromise, wsRace]);
|
|
801
|
+
} catch {
|
|
802
|
+
const ws = await wsPromise;
|
|
803
|
+
handle = new Subscription(
|
|
804
|
+
this.conn,
|
|
805
|
+
ws.subId,
|
|
806
|
+
ws.snapshot
|
|
807
|
+
);
|
|
808
|
+
return handle;
|
|
809
|
+
}
|
|
810
|
+
if (winner.kind === "ws") {
|
|
811
|
+
handle = new Subscription(
|
|
812
|
+
this.conn,
|
|
813
|
+
winner.subId,
|
|
814
|
+
winner.snapshot
|
|
815
|
+
);
|
|
816
|
+
return handle;
|
|
817
|
+
}
|
|
818
|
+
handle = new Subscription(
|
|
819
|
+
this.conn,
|
|
820
|
+
PENDING_SUB_ID,
|
|
821
|
+
winner.snapshot
|
|
822
|
+
);
|
|
823
|
+
wsPromise.then((r) => {
|
|
824
|
+
handle._deliverSnapshot(r.subId, r.snapshot);
|
|
825
|
+
}).catch((err) => {
|
|
826
|
+
handle._deliverClosed(
|
|
827
|
+
"internal_error",
|
|
828
|
+
err instanceof Error ? err.message : String(err)
|
|
829
|
+
);
|
|
830
|
+
});
|
|
831
|
+
return handle;
|
|
832
|
+
}
|
|
833
|
+
async subscribe(params, options) {
|
|
834
|
+
const merged = { locale: this.defaults.locale, ...params };
|
|
835
|
+
let handle;
|
|
836
|
+
const { subId, snapshot } = await this.conn.registerSubscription(
|
|
837
|
+
"matches.subscribe",
|
|
838
|
+
merged,
|
|
839
|
+
{
|
|
840
|
+
onEvent: (event) => handle?._deliverEvent(event),
|
|
841
|
+
onClosed: (p) => handle?._deliverClosed(p.reason, p.message),
|
|
842
|
+
onSnapshot: (newSubId, newSnap) => handle?._deliverSnapshot(newSubId, newSnap)
|
|
843
|
+
},
|
|
844
|
+
options
|
|
845
|
+
);
|
|
846
|
+
handle = new Subscription(this.conn, subId, snapshot);
|
|
847
|
+
return handle;
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
// src/resources/ai.ts
|
|
852
|
+
var Picks = class {
|
|
853
|
+
constructor(conn, defaults) {
|
|
854
|
+
this.conn = conn;
|
|
855
|
+
this.defaults = defaults;
|
|
856
|
+
}
|
|
857
|
+
conn;
|
|
858
|
+
defaults;
|
|
859
|
+
list(params = {}, options) {
|
|
860
|
+
return this.conn.call(
|
|
861
|
+
"ai.picks.list",
|
|
862
|
+
{ locale: this.defaults.locale, ...params },
|
|
863
|
+
options
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
var Recommendations = class {
|
|
868
|
+
constructor(conn, defaults) {
|
|
869
|
+
this.conn = conn;
|
|
870
|
+
this.defaults = defaults;
|
|
871
|
+
}
|
|
872
|
+
conn;
|
|
873
|
+
defaults;
|
|
874
|
+
list(params = {}, options) {
|
|
875
|
+
return this.conn.call(
|
|
876
|
+
"ai.recommendations.list",
|
|
877
|
+
{ locale: this.defaults.locale, ...params },
|
|
878
|
+
options
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
var Ai = class {
|
|
883
|
+
picks;
|
|
884
|
+
recommendations;
|
|
885
|
+
constructor(conn, defaults) {
|
|
886
|
+
this.picks = new Picks(conn, defaults);
|
|
887
|
+
this.recommendations = new Recommendations(conn, defaults);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/resources/tokens.ts
|
|
892
|
+
var Tokens = class {
|
|
893
|
+
constructor(conn) {
|
|
894
|
+
this.conn = conn;
|
|
895
|
+
}
|
|
896
|
+
conn;
|
|
897
|
+
/**
|
|
898
|
+
* Mint a short-lived JWT auth token.
|
|
899
|
+
*
|
|
900
|
+
* @param params.ttl Token lifetime in seconds. Default 600 (10 min).
|
|
901
|
+
* Server-enforced bounds: min 60, max 86400 (24h).
|
|
902
|
+
* @returns { token, expiresAt } — `token` is opaque to the customer; pass
|
|
903
|
+
* it to `@mrdoge/client`. `expiresAt` is ISO-8601.
|
|
904
|
+
*/
|
|
905
|
+
create(params = {}, options) {
|
|
906
|
+
return this.conn.call("tokens.create", params, options);
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
// src/client.ts
|
|
911
|
+
var DEFAULT_BASE_URL = "wss://api.mrdoge.co/sdk/v1";
|
|
912
|
+
function wsToHttp(url) {
|
|
913
|
+
if (url.startsWith("wss://")) return "https://" + url.slice("wss://".length);
|
|
914
|
+
if (url.startsWith("ws://")) return "http://" + url.slice("ws://".length);
|
|
915
|
+
return url;
|
|
916
|
+
}
|
|
917
|
+
var MrDoge = class {
|
|
918
|
+
regions;
|
|
919
|
+
competitions;
|
|
920
|
+
teams;
|
|
921
|
+
matches;
|
|
922
|
+
ai;
|
|
923
|
+
tokens;
|
|
924
|
+
connection;
|
|
925
|
+
http;
|
|
926
|
+
constructor(options) {
|
|
927
|
+
if (!options?.apiKey) throw new Error("MrDoge: `apiKey` is required");
|
|
928
|
+
const config = {
|
|
929
|
+
...DEFAULT_CONFIG,
|
|
930
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
931
|
+
apiKey: options.apiKey,
|
|
932
|
+
locale: options.locale,
|
|
933
|
+
timezone: options.timezone,
|
|
934
|
+
requestTimeoutMs: options.requestTimeoutMs ?? DEFAULT_CONFIG.requestTimeoutMs,
|
|
935
|
+
maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULT_CONFIG.maxReconnectAttempts,
|
|
936
|
+
reconnectBackoff: {
|
|
937
|
+
...DEFAULT_CONFIG.reconnectBackoff,
|
|
938
|
+
...options.reconnectBackoff
|
|
939
|
+
},
|
|
940
|
+
compression: options.compression ?? DEFAULT_CONFIG.compression
|
|
941
|
+
};
|
|
942
|
+
this.connection = new Connection(config);
|
|
943
|
+
this.http = (0, import_http.createHttpClient)({
|
|
944
|
+
apiKey: options.apiKey,
|
|
945
|
+
baseUrl: wsToHttp(config.baseUrl),
|
|
946
|
+
locale: options.locale,
|
|
947
|
+
timezone: options.timezone,
|
|
948
|
+
requestTimeoutMs: config.requestTimeoutMs
|
|
949
|
+
});
|
|
950
|
+
const defaults = { locale: options.locale, timezone: options.timezone };
|
|
951
|
+
this.regions = new Regions(this.connection, defaults);
|
|
952
|
+
this.competitions = new Competitions(this.connection, defaults);
|
|
953
|
+
this.teams = new Teams(this.connection, defaults);
|
|
954
|
+
this.matches = new Matches(this.connection, defaults, this.http);
|
|
955
|
+
this.ai = new Ai(this.connection, defaults);
|
|
956
|
+
this.tokens = new Tokens(this.connection);
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Listen to connection lifecycle events.
|
|
960
|
+
*/
|
|
961
|
+
on(event, fn) {
|
|
962
|
+
return this.connection.on(event, fn);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Force-open the connection now instead of waiting for the first call.
|
|
966
|
+
* Returns the welcome payload from the server.
|
|
967
|
+
*/
|
|
968
|
+
async connect() {
|
|
969
|
+
return this.connection.connect();
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Close the connection and cancel every active subscription. The client is
|
|
973
|
+
* unusable after `close()`.
|
|
974
|
+
*/
|
|
975
|
+
async close() {
|
|
976
|
+
await this.connection.close();
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
980
|
+
0 && (module.exports = {
|
|
981
|
+
AbortError,
|
|
982
|
+
ConnectionError,
|
|
983
|
+
ConnectionLimitError,
|
|
984
|
+
DEFAULT_BASE_URL,
|
|
985
|
+
DisconnectedError,
|
|
986
|
+
ForbiddenError,
|
|
987
|
+
InternalError,
|
|
988
|
+
MrDoge,
|
|
989
|
+
MrDogeError,
|
|
990
|
+
NotFoundError,
|
|
991
|
+
ProtocolError,
|
|
992
|
+
RateLimitError,
|
|
993
|
+
Subscription,
|
|
994
|
+
SubscriptionLimitError,
|
|
995
|
+
TimeoutError,
|
|
996
|
+
UnauthorizedError,
|
|
997
|
+
UnavailableError,
|
|
998
|
+
ValidationError
|
|
999
|
+
});
|
|
1000
|
+
//# sourceMappingURL=index.js.map
|