@azure/web-pubsub-chat-client 1.0.0-beta.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.
package/dist/index.js ADDED
@@ -0,0 +1,2620 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // node_modules/@typespec/ts-http-runtime/dist/esm/env.js
6
+ import process from "node:process";
7
+ function getEnvironmentVariable(name) {
8
+ return process.env[name];
9
+ }
10
+ var isDeno = typeof process.versions.deno === "string" && process.versions.deno.length > 0;
11
+ var isBun = typeof process.versions.bun === "string" && process.versions.bun.length > 0;
12
+
13
+ // node_modules/@azure/abort-controller/dist/esm/AbortError.js
14
+ var AbortError = class extends Error {
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = "AbortError";
18
+ }
19
+ };
20
+
21
+ // node_modules/@azure/core-util/dist/esm/createAbortablePromise.js
22
+ function createAbortablePromise(buildPromise, options) {
23
+ const { cleanupBeforeAbort, abortSignal, abortErrorMsg } = options ?? {};
24
+ return new Promise((resolve, reject) => {
25
+ function rejectOnAbort() {
26
+ reject(new AbortError(abortErrorMsg ?? "The operation was aborted."));
27
+ }
28
+ function removeListeners() {
29
+ abortSignal?.removeEventListener("abort", onAbort);
30
+ }
31
+ function onAbort() {
32
+ cleanupBeforeAbort?.();
33
+ removeListeners();
34
+ rejectOnAbort();
35
+ }
36
+ if (abortSignal?.aborted) {
37
+ return rejectOnAbort();
38
+ }
39
+ try {
40
+ buildPromise((x) => {
41
+ removeListeners();
42
+ resolve(x);
43
+ }, (x) => {
44
+ removeListeners();
45
+ reject(x);
46
+ });
47
+ } catch (err) {
48
+ reject(err);
49
+ }
50
+ abortSignal?.addEventListener("abort", onAbort);
51
+ });
52
+ }
53
+
54
+ // node_modules/@azure/core-util/dist/esm/delay.js
55
+ var StandardAbortMessage = "The delay was aborted.";
56
+ function delay(timeInMs, options) {
57
+ let token;
58
+ const { abortSignal, abortErrorMsg } = options ?? {};
59
+ return createAbortablePromise((resolve) => {
60
+ token = setTimeout(resolve, timeInMs);
61
+ }, {
62
+ cleanupBeforeAbort: () => clearTimeout(token),
63
+ abortSignal,
64
+ abortErrorMsg: abortErrorMsg ?? StandardAbortMessage
65
+ });
66
+ }
67
+
68
+ // node_modules/@azure/web-pubsub-client/dist/esm/webPubSubClient.js
69
+ import EventEmitter from "events";
70
+
71
+ // node_modules/@azure/web-pubsub-client/dist/esm/errors/index.js
72
+ var SendMessageError = class extends Error {
73
+ /**
74
+ * Initialize a SendMessageError
75
+ * @param message - The error message
76
+ * @param ackMessage - The ack message
77
+ */
78
+ constructor(message, options) {
79
+ super(message);
80
+ /**
81
+ * Error name
82
+ */
83
+ __publicField(this, "name");
84
+ /**
85
+ * The ack id of the message
86
+ */
87
+ __publicField(this, "ackId");
88
+ /**
89
+ * The error details from the service
90
+ */
91
+ __publicField(this, "errorDetail");
92
+ this.name = "SendMessageError";
93
+ this.ackId = options.ackId;
94
+ this.errorDetail = options.errorDetail;
95
+ }
96
+ };
97
+ var InvocationError = class extends Error {
98
+ constructor(message, options) {
99
+ super(message);
100
+ /**
101
+ * The invocation id of the request.
102
+ */
103
+ __publicField(this, "invocationId");
104
+ /**
105
+ * Error details from the service if available.
106
+ */
107
+ __publicField(this, "errorDetail");
108
+ this.name = "InvocationError";
109
+ this.invocationId = options.invocationId;
110
+ this.errorDetail = options.errorDetail;
111
+ }
112
+ };
113
+
114
+ // node_modules/@typespec/ts-http-runtime/dist/esm/logger/log.js
115
+ import { EOL } from "node:os";
116
+ import util from "node:util";
117
+ import process2 from "node:process";
118
+ function log(message, ...args) {
119
+ process2.stderr.write(`${util.format(message, ...args)}${EOL}`);
120
+ }
121
+
122
+ // node_modules/@typespec/ts-http-runtime/dist/esm/logger/debug.js
123
+ var debugEnvVariable = getEnvironmentVariable("DEBUG");
124
+ var enabledString;
125
+ var enabledNamespaces = [];
126
+ var skippedNamespaces = [];
127
+ var debuggers = [];
128
+ if (debugEnvVariable) {
129
+ enable(debugEnvVariable);
130
+ }
131
+ var debugObj = Object.assign((namespace) => {
132
+ return createDebugger(namespace);
133
+ }, {
134
+ enable,
135
+ enabled,
136
+ disable,
137
+ log
138
+ });
139
+ function enable(namespaces) {
140
+ enabledString = namespaces;
141
+ enabledNamespaces = [];
142
+ skippedNamespaces = [];
143
+ const namespaceList = namespaces.split(",").map((ns) => ns.trim());
144
+ for (const ns of namespaceList) {
145
+ if (ns.startsWith("-")) {
146
+ skippedNamespaces.push(ns.substring(1));
147
+ } else {
148
+ enabledNamespaces.push(ns);
149
+ }
150
+ }
151
+ for (const instance of debuggers) {
152
+ instance.enabled = enabled(instance.namespace);
153
+ }
154
+ }
155
+ function enabled(namespace) {
156
+ if (namespace.endsWith("*")) {
157
+ return true;
158
+ }
159
+ for (const skipped of skippedNamespaces) {
160
+ if (namespaceMatches(namespace, skipped)) {
161
+ return false;
162
+ }
163
+ }
164
+ for (const enabledNamespace of enabledNamespaces) {
165
+ if (namespaceMatches(namespace, enabledNamespace)) {
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ function namespaceMatches(namespace, patternToMatch) {
172
+ if (patternToMatch.indexOf("*") === -1) {
173
+ return namespace === patternToMatch;
174
+ }
175
+ let pattern = patternToMatch;
176
+ if (patternToMatch.indexOf("**") !== -1) {
177
+ const patternParts = [];
178
+ let lastCharacter = "";
179
+ for (const character of patternToMatch) {
180
+ if (character === "*" && lastCharacter === "*") {
181
+ continue;
182
+ } else {
183
+ lastCharacter = character;
184
+ patternParts.push(character);
185
+ }
186
+ }
187
+ pattern = patternParts.join("");
188
+ }
189
+ let namespaceIndex = 0;
190
+ let patternIndex = 0;
191
+ const patternLength = pattern.length;
192
+ const namespaceLength = namespace.length;
193
+ let lastWildcard = -1;
194
+ let lastWildcardNamespace = -1;
195
+ while (namespaceIndex < namespaceLength && patternIndex < patternLength) {
196
+ if (pattern[patternIndex] === "*") {
197
+ lastWildcard = patternIndex;
198
+ patternIndex++;
199
+ if (patternIndex === patternLength) {
200
+ return true;
201
+ }
202
+ while (namespace[namespaceIndex] !== pattern[patternIndex]) {
203
+ namespaceIndex++;
204
+ if (namespaceIndex === namespaceLength) {
205
+ return false;
206
+ }
207
+ }
208
+ lastWildcardNamespace = namespaceIndex;
209
+ namespaceIndex++;
210
+ patternIndex++;
211
+ continue;
212
+ } else if (pattern[patternIndex] === namespace[namespaceIndex]) {
213
+ patternIndex++;
214
+ namespaceIndex++;
215
+ } else if (lastWildcard >= 0) {
216
+ patternIndex = lastWildcard + 1;
217
+ namespaceIndex = lastWildcardNamespace + 1;
218
+ if (namespaceIndex === namespaceLength) {
219
+ return false;
220
+ }
221
+ while (namespace[namespaceIndex] !== pattern[patternIndex]) {
222
+ namespaceIndex++;
223
+ if (namespaceIndex === namespaceLength) {
224
+ return false;
225
+ }
226
+ }
227
+ lastWildcardNamespace = namespaceIndex;
228
+ namespaceIndex++;
229
+ patternIndex++;
230
+ continue;
231
+ } else {
232
+ return false;
233
+ }
234
+ }
235
+ const namespaceDone = namespaceIndex === namespace.length;
236
+ const patternDone = patternIndex === pattern.length;
237
+ const trailingWildCard = patternIndex === pattern.length - 1 && pattern[patternIndex] === "*";
238
+ return namespaceDone && (patternDone || trailingWildCard);
239
+ }
240
+ function disable() {
241
+ const result = enabledString || "";
242
+ enable("");
243
+ return result;
244
+ }
245
+ function createDebugger(namespace) {
246
+ const newDebugger = Object.assign(debug, {
247
+ enabled: enabled(namespace),
248
+ destroy,
249
+ log: debugObj.log,
250
+ namespace,
251
+ extend
252
+ });
253
+ function debug(...args) {
254
+ if (!newDebugger.enabled) {
255
+ return;
256
+ }
257
+ if (args.length > 0) {
258
+ args[0] = `${namespace} ${args[0]}`;
259
+ }
260
+ newDebugger.log(...args);
261
+ }
262
+ debuggers.push(newDebugger);
263
+ return newDebugger;
264
+ }
265
+ function destroy() {
266
+ const index = debuggers.indexOf(this);
267
+ if (index >= 0) {
268
+ debuggers.splice(index, 1);
269
+ return true;
270
+ }
271
+ return false;
272
+ }
273
+ function extend(namespace) {
274
+ const newDebugger = createDebugger(`${this.namespace}:${namespace}`);
275
+ newDebugger.log = this.log;
276
+ return newDebugger;
277
+ }
278
+ var debug_default = debugObj;
279
+
280
+ // node_modules/@typespec/ts-http-runtime/dist/esm/logger/logger.js
281
+ var TYPESPEC_RUNTIME_LOG_LEVELS = ["verbose", "info", "warning", "error"];
282
+ var levelMap = {
283
+ verbose: 400,
284
+ info: 300,
285
+ warning: 200,
286
+ error: 100
287
+ };
288
+ function patchLogMethod(parent, child) {
289
+ child.log = (...args) => {
290
+ parent.log(...args);
291
+ };
292
+ }
293
+ function isTypeSpecRuntimeLogLevel(level) {
294
+ return TYPESPEC_RUNTIME_LOG_LEVELS.includes(level);
295
+ }
296
+ function createLoggerContext(options) {
297
+ const registeredLoggers = /* @__PURE__ */ new Set();
298
+ const logLevelFromEnv = getEnvironmentVariable(options.logLevelEnvVarName);
299
+ let logLevel;
300
+ const clientLogger = debug_default(options.namespace);
301
+ clientLogger.log = (...args) => {
302
+ debug_default.log(...args);
303
+ };
304
+ function contextSetLogLevel(level) {
305
+ if (level && !isTypeSpecRuntimeLogLevel(level)) {
306
+ throw new Error(`Unknown log level '${level}'. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(",")}`);
307
+ }
308
+ logLevel = level;
309
+ const enabledNamespaces2 = [];
310
+ for (const logger3 of registeredLoggers) {
311
+ if (shouldEnable(logger3)) {
312
+ enabledNamespaces2.push(logger3.namespace);
313
+ }
314
+ }
315
+ debug_default.enable(enabledNamespaces2.join(","));
316
+ }
317
+ if (logLevelFromEnv) {
318
+ if (isTypeSpecRuntimeLogLevel(logLevelFromEnv)) {
319
+ contextSetLogLevel(logLevelFromEnv);
320
+ } else {
321
+ console.error(`${options.logLevelEnvVarName} set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(", ")}.`);
322
+ }
323
+ }
324
+ function shouldEnable(logger3) {
325
+ return Boolean(logLevel && levelMap[logger3.level] <= levelMap[logLevel]);
326
+ }
327
+ function createLogger(parent, level) {
328
+ const logger3 = Object.assign(parent.extend(level), {
329
+ level
330
+ });
331
+ patchLogMethod(parent, logger3);
332
+ if (shouldEnable(logger3)) {
333
+ const enabledNamespaces2 = debug_default.disable();
334
+ debug_default.enable(enabledNamespaces2 + "," + logger3.namespace);
335
+ }
336
+ registeredLoggers.add(logger3);
337
+ return logger3;
338
+ }
339
+ function contextGetLogLevel() {
340
+ return logLevel;
341
+ }
342
+ function contextCreateClientLogger(namespace) {
343
+ const clientRootLogger = clientLogger.extend(namespace);
344
+ patchLogMethod(clientLogger, clientRootLogger);
345
+ return {
346
+ error: createLogger(clientRootLogger, "error"),
347
+ warning: createLogger(clientRootLogger, "warning"),
348
+ info: createLogger(clientRootLogger, "info"),
349
+ verbose: createLogger(clientRootLogger, "verbose")
350
+ };
351
+ }
352
+ return {
353
+ setLogLevel: contextSetLogLevel,
354
+ getLogLevel: contextGetLogLevel,
355
+ createClientLogger: contextCreateClientLogger,
356
+ logger: clientLogger
357
+ };
358
+ }
359
+ var context = createLoggerContext({
360
+ logLevelEnvVarName: "TYPESPEC_RUNTIME_LOG_LEVEL",
361
+ namespace: "typeSpecRuntime"
362
+ });
363
+ var TypeSpecRuntimeLogger = context.logger;
364
+
365
+ // node_modules/@azure/logger/dist/esm/index.js
366
+ var context2 = createLoggerContext({
367
+ logLevelEnvVarName: "AZURE_LOG_LEVEL",
368
+ namespace: "azure"
369
+ });
370
+ var AzureLogger = context2.logger;
371
+ function createClientLogger(namespace) {
372
+ return context2.createClientLogger(namespace);
373
+ }
374
+
375
+ // node_modules/@azure/web-pubsub-client/dist/esm/logger.js
376
+ var logger = createClientLogger("web-pubsub-client");
377
+
378
+ // node_modules/@azure/web-pubsub-client/dist/esm/protocols/jsonProtocolBase.js
379
+ import { Buffer as Buffer2 } from "buffer";
380
+ function parseMessages(input) {
381
+ if (typeof input !== "string") {
382
+ throw new Error("Invalid input for JSON hub protocol. Expected a string.");
383
+ }
384
+ if (!input) {
385
+ throw new Error("No input");
386
+ }
387
+ const parsedMessage = JSON.parse(input);
388
+ const typedMessage = parsedMessage;
389
+ let returnMessage;
390
+ if (typedMessage.type === "system") {
391
+ if (typedMessage.event === "connected") {
392
+ returnMessage = { ...parsedMessage, kind: "connected" };
393
+ } else if (typedMessage.event === "disconnected") {
394
+ returnMessage = { ...parsedMessage, kind: "disconnected" };
395
+ } else {
396
+ return null;
397
+ }
398
+ } else if (typedMessage.type === "message") {
399
+ if (typedMessage.from === "group") {
400
+ const data = parsePayload(parsedMessage.data, parsedMessage.dataType);
401
+ if (data === null) {
402
+ return null;
403
+ }
404
+ returnMessage = { ...parsedMessage, data, kind: "groupData" };
405
+ } else if (typedMessage.from === "server") {
406
+ const data = parsePayload(parsedMessage.data, parsedMessage.dataType);
407
+ if (data === null) {
408
+ return null;
409
+ }
410
+ returnMessage = {
411
+ ...parsedMessage,
412
+ data,
413
+ kind: "serverData"
414
+ };
415
+ } else {
416
+ return null;
417
+ }
418
+ } else if (typedMessage.type === "ack") {
419
+ returnMessage = { ...parsedMessage, kind: "ack" };
420
+ } else if (typedMessage.type === "invokeResponse") {
421
+ let data;
422
+ if (parsedMessage.dataType != null) {
423
+ const parsedData = parsePayload(parsedMessage.data, parsedMessage.dataType);
424
+ if (parsedData === null) {
425
+ return null;
426
+ }
427
+ data = parsedData;
428
+ }
429
+ returnMessage = {
430
+ kind: "invokeResponse",
431
+ invocationId: parsedMessage.invocationId,
432
+ success: parsedMessage.success,
433
+ dataType: parsedMessage.dataType,
434
+ data,
435
+ error: parsedMessage.error
436
+ };
437
+ } else if (typedMessage.type === "cancelInvocation") {
438
+ returnMessage = {
439
+ ...parsedMessage,
440
+ kind: "cancelInvocation"
441
+ };
442
+ } else if (typedMessage.type === "pong") {
443
+ returnMessage = { ...parsedMessage, kind: "pong" };
444
+ } else {
445
+ return null;
446
+ }
447
+ return returnMessage;
448
+ }
449
+ function writeMessage(message) {
450
+ let data;
451
+ switch (message.kind) {
452
+ case "joinGroup": {
453
+ data = { type: "joinGroup", group: message.group, ackId: message.ackId };
454
+ break;
455
+ }
456
+ case "leaveGroup": {
457
+ data = { type: "leaveGroup", group: message.group, ackId: message.ackId };
458
+ break;
459
+ }
460
+ case "sendEvent": {
461
+ data = {
462
+ type: "event",
463
+ event: message.event,
464
+ ackId: message.ackId,
465
+ dataType: message.dataType,
466
+ data: getPayload(message.data, message.dataType)
467
+ };
468
+ break;
469
+ }
470
+ case "sendToGroup": {
471
+ data = {
472
+ type: "sendToGroup",
473
+ group: message.group,
474
+ ackId: message.ackId,
475
+ dataType: message.dataType,
476
+ data: getPayload(message.data, message.dataType),
477
+ noEcho: message.noEcho
478
+ };
479
+ break;
480
+ }
481
+ case "sequenceAck": {
482
+ data = { type: "sequenceAck", sequenceId: message.sequenceId };
483
+ break;
484
+ }
485
+ case "invoke": {
486
+ const invokePayload = {
487
+ type: "invoke",
488
+ invocationId: message.invocationId,
489
+ target: message.target,
490
+ event: message.event
491
+ };
492
+ if (message.dataType != null && message.data != null) {
493
+ invokePayload.dataType = message.dataType;
494
+ invokePayload.data = getPayload(message.data, message.dataType);
495
+ }
496
+ data = invokePayload;
497
+ break;
498
+ }
499
+ case "invokeResponse": {
500
+ const invokeResponse = {
501
+ type: "invokeResponse",
502
+ invocationId: message.invocationId,
503
+ success: message.success,
504
+ error: message.error
505
+ };
506
+ if (message.dataType != null && message.data != null) {
507
+ invokeResponse.dataType = message.dataType;
508
+ invokeResponse.data = getPayload(message.data, message.dataType);
509
+ }
510
+ data = invokeResponse;
511
+ break;
512
+ }
513
+ case "cancelInvocation": {
514
+ data = {
515
+ type: "cancelInvocation",
516
+ invocationId: message.invocationId
517
+ };
518
+ break;
519
+ }
520
+ case "ping": {
521
+ data = { type: "ping" };
522
+ break;
523
+ }
524
+ default: {
525
+ throw new Error(`Unsupported type: ${message.kind}`);
526
+ }
527
+ }
528
+ return JSON.stringify(data);
529
+ }
530
+ function getPayload(data, dataType) {
531
+ switch (dataType) {
532
+ case "text": {
533
+ if (typeof data !== "string") {
534
+ throw new TypeError("Message must be a string.");
535
+ }
536
+ return data;
537
+ }
538
+ case "json": {
539
+ return data;
540
+ }
541
+ case "binary":
542
+ case "protobuf": {
543
+ if (data instanceof ArrayBuffer) {
544
+ return Buffer2.from(data).toString("base64");
545
+ }
546
+ throw new TypeError("Message must be a ArrayBuffer");
547
+ }
548
+ }
549
+ }
550
+ function parsePayload(data, dataType) {
551
+ if (dataType === "text") {
552
+ if (typeof data !== "string") {
553
+ throw new TypeError("Message must be a string when dataType is text");
554
+ }
555
+ return data;
556
+ } else if (dataType === "json") {
557
+ return data;
558
+ } else if (dataType === "binary" || dataType === "protobuf") {
559
+ const buf = Buffer2.from(data, "base64");
560
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
561
+ } else {
562
+ return null;
563
+ }
564
+ }
565
+
566
+ // node_modules/@azure/web-pubsub-client/dist/esm/protocols/webPubSubJsonReliableProtocol.js
567
+ var WebPubSubJsonReliableProtocolImpl = class {
568
+ constructor() {
569
+ /**
570
+ * True if the protocol supports reliable features
571
+ */
572
+ __publicField(this, "isReliableSubProtocol", true);
573
+ /**
574
+ * The name of subprotocol. Name will be used in websocket subprotocol
575
+ */
576
+ __publicField(this, "name", "json.reliable.webpubsub.azure.v1");
577
+ }
578
+ /**
579
+ * Creates WebPubSubMessage objects from the specified serialized representation.
580
+ * @param input - The serialized representation
581
+ */
582
+ parseMessages(input) {
583
+ return parseMessages(input);
584
+ }
585
+ /**
586
+ * Write WebPubSubMessage to string
587
+ * @param message - The message to be written
588
+ */
589
+ writeMessage(message) {
590
+ return writeMessage(message);
591
+ }
592
+ };
593
+
594
+ // node_modules/@azure/web-pubsub-client/dist/esm/protocols/index.js
595
+ var WebPubSubJsonReliableProtocol = () => {
596
+ return new WebPubSubJsonReliableProtocolImpl();
597
+ };
598
+
599
+ // node_modules/@azure/web-pubsub-client/dist/esm/websocket/websocketClient.js
600
+ import WebSocket from "ws";
601
+ var WebSocketClient = class {
602
+ constructor(uri, protocolName) {
603
+ __publicField(this, "_socket");
604
+ this._socket = new WebSocket(uri, protocolName);
605
+ this._socket.binaryType = "arraybuffer";
606
+ }
607
+ onopen(fn) {
608
+ this._socket.onopen = fn;
609
+ }
610
+ onclose(fn) {
611
+ this._socket.onclose = (event) => fn(event.code, event.reason);
612
+ }
613
+ onerror(fn) {
614
+ this._socket.onerror = (event) => fn(event.error);
615
+ }
616
+ onmessage(fn) {
617
+ this._socket.onmessage = (event) => fn(event.data);
618
+ }
619
+ close(code, reason) {
620
+ this._socket.close(code, reason);
621
+ }
622
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
623
+ send(data, _) {
624
+ return new Promise((resolve, reject) => {
625
+ this._socket.send(data, (err) => {
626
+ if (err) {
627
+ reject(err);
628
+ } else {
629
+ resolve();
630
+ }
631
+ });
632
+ });
633
+ }
634
+ isOpen() {
635
+ return this._socket.readyState === WebSocket.OPEN;
636
+ }
637
+ };
638
+ var WebSocketClientFactory = class {
639
+ create(uri, protocolName) {
640
+ return new WebSocketClient(uri, protocolName);
641
+ }
642
+ };
643
+
644
+ // node_modules/@azure/web-pubsub-client/dist/esm/utils/abortablePromise.js
645
+ async function abortablePromise(promise, signal) {
646
+ if (signal.aborted) {
647
+ throw new AbortError("The operation was aborted.");
648
+ }
649
+ let onAbort;
650
+ const p = new Promise((_, reject) => {
651
+ onAbort = () => {
652
+ reject(new AbortError("The operation was aborted."));
653
+ };
654
+ signal.addEventListener("abort", onAbort);
655
+ });
656
+ try {
657
+ return await Promise.race([promise, p]);
658
+ } finally {
659
+ signal.removeEventListener("abort", onAbort);
660
+ }
661
+ }
662
+
663
+ // node_modules/@azure/web-pubsub-client/dist/esm/ackManager.js
664
+ var AckManager = class {
665
+ constructor(initialAckId = 0) {
666
+ __publicField(this, "_ackEntries", /* @__PURE__ */ new Map());
667
+ __publicField(this, "_ackId");
668
+ this._ackId = initialAckId;
669
+ }
670
+ registerAck(ackId) {
671
+ const resolvedAckId = ackId ?? this._generateAckId();
672
+ let entry = this._ackEntries.get(resolvedAckId);
673
+ if (!entry) {
674
+ entry = new AckEntity(resolvedAckId);
675
+ this._ackEntries.set(resolvedAckId, entry);
676
+ }
677
+ const ackEntry = entry;
678
+ return {
679
+ ackId: resolvedAckId,
680
+ wait: (abortSignal) => this._waitForEntry(ackEntry, abortSignal)
681
+ };
682
+ }
683
+ resolveAck(ackId, result) {
684
+ const entry = this._ackEntries.get(ackId);
685
+ if (!entry) {
686
+ return false;
687
+ }
688
+ this._ackEntries.delete(ackId);
689
+ entry.resolve(result);
690
+ return true;
691
+ }
692
+ rejectAck(ackId, reason) {
693
+ const entry = this._ackEntries.get(ackId);
694
+ if (!entry) {
695
+ return false;
696
+ }
697
+ this._ackEntries.delete(ackId);
698
+ entry.reject(reason);
699
+ return true;
700
+ }
701
+ discard(ackId) {
702
+ this._ackEntries.delete(ackId);
703
+ }
704
+ rejectAll(createReason) {
705
+ this._ackEntries.forEach((entry, ackId) => {
706
+ if (this._ackEntries.delete(ackId)) {
707
+ entry.reject(createReason(ackId));
708
+ }
709
+ });
710
+ }
711
+ _waitForEntry(entry, abortSignal) {
712
+ if (!abortSignal) {
713
+ return entry.promise();
714
+ }
715
+ return abortablePromise(entry.promise(), abortSignal).catch((err) => {
716
+ if (err instanceof Error && err.name === "AbortError") {
717
+ throw new SendMessageError("Cancelled by abortSignal", { ackId: entry.ackId });
718
+ }
719
+ throw err;
720
+ });
721
+ }
722
+ _generateAckId() {
723
+ this._ackId += 1;
724
+ return this._ackId;
725
+ }
726
+ };
727
+ var AckEntity = class {
728
+ constructor(ackId) {
729
+ __publicField(this, "_promise");
730
+ __publicField(this, "_resolve");
731
+ __publicField(this, "_reject");
732
+ this.ackId = ackId;
733
+ this._promise = new Promise((resolve, reject) => {
734
+ this._resolve = resolve;
735
+ this._reject = reject;
736
+ });
737
+ }
738
+ promise() {
739
+ return this._promise;
740
+ }
741
+ resolve(value) {
742
+ const callback = this._resolve;
743
+ if (!callback) {
744
+ return;
745
+ }
746
+ this._resolve = void 0;
747
+ this._reject = void 0;
748
+ callback(value);
749
+ }
750
+ reject(reason) {
751
+ const callback = this._reject;
752
+ if (!callback) {
753
+ return;
754
+ }
755
+ this._resolve = void 0;
756
+ this._reject = void 0;
757
+ callback(reason);
758
+ }
759
+ };
760
+
761
+ // node_modules/@azure/web-pubsub-client/dist/esm/invocationManager.js
762
+ var InvocationManager = class {
763
+ constructor() {
764
+ __publicField(this, "_entries", /* @__PURE__ */ new Map());
765
+ __publicField(this, "_nextId", 0);
766
+ }
767
+ registerInvocation(invocationId) {
768
+ const resolvedId = invocationId ?? this._generateInvocationId();
769
+ if (this._entries.has(resolvedId)) {
770
+ throw new InvocationError("Invocation id is already registered.", {
771
+ invocationId: resolvedId
772
+ });
773
+ }
774
+ const entity = new InvocationEntity(resolvedId);
775
+ this._entries.set(resolvedId, entity);
776
+ return {
777
+ invocationId: resolvedId,
778
+ wait: (options) => this._waitForEntry(entity, options)
779
+ };
780
+ }
781
+ resolveInvocation(message) {
782
+ const entry = this._entries.get(message.invocationId);
783
+ if (!entry) {
784
+ return false;
785
+ }
786
+ this._entries.delete(message.invocationId);
787
+ entry.resolve(message);
788
+ return true;
789
+ }
790
+ rejectInvocation(invocationId, reason) {
791
+ const entry = this._entries.get(invocationId);
792
+ if (!entry) {
793
+ return false;
794
+ }
795
+ this._entries.delete(invocationId);
796
+ entry.reject(reason);
797
+ return true;
798
+ }
799
+ discard(invocationId) {
800
+ this._entries.delete(invocationId);
801
+ }
802
+ rejectAll(createReason) {
803
+ this._entries.forEach((entry, invocationId) => {
804
+ if (this._entries.delete(invocationId)) {
805
+ entry.reject(createReason(invocationId));
806
+ }
807
+ });
808
+ }
809
+ _waitForEntry(entry, options) {
810
+ const waitPromise = entry.promise();
811
+ const abortSignal = options?.abortSignal;
812
+ if (!abortSignal) {
813
+ return waitPromise;
814
+ }
815
+ if (abortSignal.aborted) {
816
+ if (this._entries.delete(entry.invocationId)) {
817
+ entry.reject(this._createAbortError(entry.invocationId));
818
+ }
819
+ return waitPromise;
820
+ }
821
+ return new Promise((resolve, reject) => {
822
+ const onAbort = () => {
823
+ abortSignal.removeEventListener("abort", onAbort);
824
+ if (this._entries.delete(entry.invocationId)) {
825
+ entry.reject(this._createAbortError(entry.invocationId));
826
+ }
827
+ };
828
+ abortSignal.addEventListener("abort", onAbort);
829
+ waitPromise.then((result) => {
830
+ abortSignal.removeEventListener("abort", onAbort);
831
+ return resolve(result);
832
+ }).catch((err) => {
833
+ abortSignal.removeEventListener("abort", onAbort);
834
+ return reject(err);
835
+ });
836
+ });
837
+ }
838
+ _generateInvocationId() {
839
+ this._nextId += 1;
840
+ return this._nextId.toString();
841
+ }
842
+ _createAbortError(invocationId) {
843
+ return new InvocationError("Invocation cancelled by abortSignal.", {
844
+ invocationId
845
+ });
846
+ }
847
+ };
848
+ var InvocationEntity = class {
849
+ constructor(invocationId) {
850
+ __publicField(this, "_promise");
851
+ __publicField(this, "_resolve");
852
+ __publicField(this, "_reject");
853
+ this.invocationId = invocationId;
854
+ this._promise = new Promise((resolve, reject) => {
855
+ this._resolve = resolve;
856
+ this._reject = reject;
857
+ });
858
+ }
859
+ promise() {
860
+ return this._promise;
861
+ }
862
+ resolve(value) {
863
+ const callback = this._resolve;
864
+ if (!callback) {
865
+ return;
866
+ }
867
+ this._resolve = void 0;
868
+ this._reject = void 0;
869
+ callback(value);
870
+ }
871
+ reject(reason) {
872
+ const callback = this._reject;
873
+ if (!callback) {
874
+ return;
875
+ }
876
+ this._resolve = void 0;
877
+ this._reject = void 0;
878
+ callback(reason);
879
+ }
880
+ };
881
+
882
+ // node_modules/@azure/web-pubsub-client/dist/esm/webPubSubClient.js
883
+ var WebPubSubClient = class {
884
+ constructor(credential, options) {
885
+ __publicField(this, "_protocol");
886
+ __publicField(this, "_credential");
887
+ __publicField(this, "_options");
888
+ __publicField(this, "_groupMap");
889
+ __publicField(this, "_ackManager");
890
+ __publicField(this, "_invocationManager");
891
+ __publicField(this, "_sequenceId");
892
+ __publicField(this, "_messageRetryPolicy");
893
+ __publicField(this, "_reconnectRetryPolicy");
894
+ __publicField(this, "_quickSequenceAckDiff", 300);
895
+ // The timeout for keep alive
896
+ __publicField(this, "_keepAliveTimeoutInMs");
897
+ // The interval at which to send keep-alive ping messages to the runtime
898
+ __publicField(this, "_keepAliveIntervalInMs");
899
+ __publicField(this, "_emitter", new EventEmitter());
900
+ __publicField(this, "_state");
901
+ __publicField(this, "_isStopping", false);
902
+ __publicField(this, "_pingKeepaliveTask");
903
+ __publicField(this, "_timeoutMonitorTask");
904
+ // connection lifetime
905
+ __publicField(this, "_wsClient");
906
+ __publicField(this, "_uri");
907
+ __publicField(this, "_lastCloseEvent");
908
+ __publicField(this, "_lastDisconnectedMessage");
909
+ __publicField(this, "_connectionId");
910
+ __publicField(this, "_reconnectionToken");
911
+ __publicField(this, "_isInitialConnected", false);
912
+ __publicField(this, "_sequenceAckTask");
913
+ __publicField(this, "_lastMessageReceived", Date.now());
914
+ if (typeof credential === "string") {
915
+ this._credential = { getClientAccessUrl: credential };
916
+ } else {
917
+ this._credential = credential;
918
+ }
919
+ if (options == null) {
920
+ options = {};
921
+ }
922
+ this._buildDefaultOptions(options);
923
+ this._options = options;
924
+ this._messageRetryPolicy = new RetryPolicy(this._options.messageRetryOptions);
925
+ this._reconnectRetryPolicy = new RetryPolicy(this._options.reconnectRetryOptions);
926
+ this._protocol = this._options.protocol;
927
+ this._groupMap = /* @__PURE__ */ new Map();
928
+ this._ackManager = new AckManager();
929
+ this._invocationManager = new InvocationManager();
930
+ this._sequenceId = new SequenceId();
931
+ this._keepAliveTimeoutInMs = this._options.keepAliveTimeoutInMs ?? 12e4;
932
+ this._keepAliveIntervalInMs = this._options.keepAliveIntervalInMs ?? 2e4;
933
+ this._state = "Stopped";
934
+ }
935
+ /**
936
+ * Start to start to the service.
937
+ * @param abortSignal - The abort signal
938
+ */
939
+ async start(options) {
940
+ if (this._isStopping) {
941
+ throw new Error("Can't start a client during stopping");
942
+ }
943
+ if (this._state !== "Stopped") {
944
+ throw new Error("Client can be only started when it's Stopped");
945
+ }
946
+ let abortSignal;
947
+ if (options) {
948
+ abortSignal = options.abortSignal;
949
+ }
950
+ if (!this._pingKeepaliveTask && this._keepAliveIntervalInMs > 0) {
951
+ this._pingKeepaliveTask = this._getPingKeepaliveTask();
952
+ }
953
+ if (!this._timeoutMonitorTask && this._keepAliveTimeoutInMs > 0) {
954
+ this._timeoutMonitorTask = this._getTimeoutMonitorTask();
955
+ }
956
+ try {
957
+ await this._startCore(abortSignal);
958
+ } catch (err) {
959
+ this._changeState(
960
+ "Stopped"
961
+ /* Stopped */
962
+ );
963
+ this._disposeKeepaliveTasks();
964
+ this._isStopping = false;
965
+ throw err;
966
+ }
967
+ }
968
+ async _startFromRestarting(abortSignal) {
969
+ if (this._state !== "Disconnected") {
970
+ throw new Error("Client can be only restarted when it's Disconnected");
971
+ }
972
+ try {
973
+ logger.verbose("Staring reconnecting.");
974
+ await this._startCore(abortSignal);
975
+ } catch (err) {
976
+ this._changeState(
977
+ "Disconnected"
978
+ /* Disconnected */
979
+ );
980
+ throw err;
981
+ }
982
+ }
983
+ async _startCore(abortSignal) {
984
+ this._changeState(
985
+ "Connecting"
986
+ /* Connecting */
987
+ );
988
+ logger.info("Staring a new connection");
989
+ this._sequenceId.reset();
990
+ this._isInitialConnected = false;
991
+ this._lastCloseEvent = void 0;
992
+ this._lastDisconnectedMessage = void 0;
993
+ this._connectionId = void 0;
994
+ this._reconnectionToken = void 0;
995
+ this._uri = void 0;
996
+ if (typeof this._credential.getClientAccessUrl === "string") {
997
+ this._uri = this._credential.getClientAccessUrl;
998
+ } else {
999
+ this._uri = await this._credential.getClientAccessUrl({
1000
+ abortSignal
1001
+ });
1002
+ }
1003
+ if (typeof this._uri !== "string") {
1004
+ throw new Error(
1005
+ `The clientAccessUrl must be a string but currently it's ${typeof this._uri}`
1006
+ );
1007
+ }
1008
+ await this._connectCore(this._uri);
1009
+ }
1010
+ /**
1011
+ * Stop the client.
1012
+ */
1013
+ stop() {
1014
+ if (this._state === "Stopped" || this._isStopping) {
1015
+ return;
1016
+ }
1017
+ this._isStopping = true;
1018
+ if (this._wsClient && this._wsClient.isOpen()) {
1019
+ this._wsClient.close();
1020
+ } else {
1021
+ this._isStopping = false;
1022
+ }
1023
+ this._disposeKeepaliveTasks();
1024
+ }
1025
+ _disposeKeepaliveTasks() {
1026
+ if (this._pingKeepaliveTask) {
1027
+ this._pingKeepaliveTask.abort();
1028
+ this._pingKeepaliveTask = void 0;
1029
+ }
1030
+ if (this._timeoutMonitorTask) {
1031
+ this._timeoutMonitorTask.abort();
1032
+ this._timeoutMonitorTask = void 0;
1033
+ }
1034
+ }
1035
+ on(event, listener) {
1036
+ this._emitter.on(event, listener);
1037
+ }
1038
+ off(event, listener) {
1039
+ this._emitter.removeListener(event, listener);
1040
+ }
1041
+ _emitEvent(event, args) {
1042
+ this._emitter.emit(event, args);
1043
+ }
1044
+ /**
1045
+ * Send custom event to server.
1046
+ * @param eventName - The event name
1047
+ * @param content - The data content
1048
+ * @param dataType - The data type
1049
+ * @param options - The options
1050
+ * @param abortSignal - The abort signal
1051
+ */
1052
+ async sendEvent(eventName, content, dataType, options) {
1053
+ return this._operationExecuteWithRetry(
1054
+ () => this._sendEventAttempt(eventName, content, dataType, options),
1055
+ options?.abortSignal
1056
+ );
1057
+ }
1058
+ async _sendEventAttempt(eventName, content, dataType, options) {
1059
+ const fireAndForget = options?.fireAndForget ?? false;
1060
+ if (!fireAndForget) {
1061
+ return this._sendMessageWithAckId(
1062
+ (id) => {
1063
+ return {
1064
+ kind: "sendEvent",
1065
+ dataType,
1066
+ data: content,
1067
+ ackId: id,
1068
+ event: eventName
1069
+ };
1070
+ },
1071
+ options?.ackId,
1072
+ options?.abortSignal
1073
+ );
1074
+ }
1075
+ const message = {
1076
+ kind: "sendEvent",
1077
+ dataType,
1078
+ data: content,
1079
+ event: eventName
1080
+ };
1081
+ await this._sendMessage(message, options?.abortSignal);
1082
+ return { isDuplicated: false };
1083
+ }
1084
+ async _invokeEventAttempt(eventName, content, dataType, options) {
1085
+ const invokeOptions = options ?? {};
1086
+ const { invocationId, wait } = this._invocationManager.registerInvocation(
1087
+ invokeOptions.invocationId
1088
+ );
1089
+ const invokeMessage = {
1090
+ kind: "invoke",
1091
+ invocationId,
1092
+ target: "event",
1093
+ event: eventName,
1094
+ dataType,
1095
+ data: content
1096
+ };
1097
+ const responsePromise = wait({
1098
+ abortSignal: invokeOptions.abortSignal
1099
+ });
1100
+ try {
1101
+ await this._sendMessage(invokeMessage, invokeOptions.abortSignal);
1102
+ } catch (err) {
1103
+ const invocationError = err instanceof InvocationError ? err : new InvocationError(
1104
+ err instanceof Error ? err.message : "Failed to send invocation message.",
1105
+ {
1106
+ invocationId
1107
+ }
1108
+ );
1109
+ this._invocationManager.rejectInvocation(invocationId, invocationError);
1110
+ void responsePromise.catch(() => {
1111
+ });
1112
+ throw invocationError;
1113
+ }
1114
+ try {
1115
+ const response = await responsePromise;
1116
+ return this._mapInvokeResponse(response);
1117
+ } catch (err) {
1118
+ const shouldCancel = err instanceof InvocationError && err.errorDetail == null || invokeOptions.abortSignal?.aborted === true;
1119
+ if (shouldCancel) {
1120
+ await this._sendCancelInvocation(invocationId).catch(() => {
1121
+ });
1122
+ }
1123
+ throw err;
1124
+ } finally {
1125
+ this._invocationManager.discard(invocationId);
1126
+ }
1127
+ }
1128
+ /**
1129
+ * Invoke an upstream event and wait for the correlated response.
1130
+ * @param eventName - The event name
1131
+ * @param content - The payload
1132
+ * @param dataType - The payload type
1133
+ * @param options - Invoke options
1134
+ */
1135
+ async invokeEvent(eventName, content, dataType, options) {
1136
+ return this._operationExecuteWithRetry(
1137
+ () => this._invokeEventAttempt(eventName, content, dataType, options),
1138
+ options?.abortSignal
1139
+ );
1140
+ }
1141
+ /**
1142
+ * Join the client to group
1143
+ * @param groupName - The group name
1144
+ * @param options - The join group options
1145
+ */
1146
+ async joinGroup(groupName, options) {
1147
+ return this._operationExecuteWithRetry(
1148
+ () => this._joinGroupAttempt(groupName, options),
1149
+ options?.abortSignal
1150
+ );
1151
+ }
1152
+ async _joinGroupAttempt(groupName, options) {
1153
+ const group = this._getOrAddGroup(groupName);
1154
+ const result = await this._joinGroupCore(groupName, options);
1155
+ group.isJoined = true;
1156
+ return result;
1157
+ }
1158
+ async _joinGroupCore(groupName, options) {
1159
+ return this._sendMessageWithAckId(
1160
+ (id) => {
1161
+ return {
1162
+ group: groupName,
1163
+ ackId: id,
1164
+ kind: "joinGroup"
1165
+ };
1166
+ },
1167
+ options?.ackId,
1168
+ options?.abortSignal
1169
+ );
1170
+ }
1171
+ /**
1172
+ * Leave the client from group
1173
+ * @param groupName - The group name
1174
+ * @param ackId - The optional ackId. If not specified, client will generate one.
1175
+ * @param abortSignal - The abort signal
1176
+ */
1177
+ async leaveGroup(groupName, options) {
1178
+ return this._operationExecuteWithRetry(
1179
+ () => this._leaveGroupAttempt(groupName, options),
1180
+ options?.abortSignal
1181
+ );
1182
+ }
1183
+ async _leaveGroupAttempt(groupName, options) {
1184
+ const group = this._getOrAddGroup(groupName);
1185
+ const result = await this._sendMessageWithAckId(
1186
+ (id) => {
1187
+ return {
1188
+ group: groupName,
1189
+ ackId: id,
1190
+ kind: "leaveGroup"
1191
+ };
1192
+ },
1193
+ options?.ackId,
1194
+ options?.abortSignal
1195
+ );
1196
+ group.isJoined = false;
1197
+ return result;
1198
+ }
1199
+ /**
1200
+ * Send message to group.
1201
+ * @param groupName - The group name
1202
+ * @param content - The data content
1203
+ * @param dataType - The data type
1204
+ * @param options - The options
1205
+ * @param abortSignal - The abort signal
1206
+ */
1207
+ async sendToGroup(groupName, content, dataType, options) {
1208
+ return this._operationExecuteWithRetry(
1209
+ () => this._sendToGroupAttempt(groupName, content, dataType, options),
1210
+ options?.abortSignal
1211
+ );
1212
+ }
1213
+ async _sendToGroupAttempt(groupName, content, dataType, options) {
1214
+ const fireAndForget = options?.fireAndForget ?? false;
1215
+ const noEcho = options?.noEcho ?? false;
1216
+ if (!fireAndForget) {
1217
+ return this._sendMessageWithAckId(
1218
+ (id) => {
1219
+ return {
1220
+ kind: "sendToGroup",
1221
+ group: groupName,
1222
+ dataType,
1223
+ data: content,
1224
+ ackId: id,
1225
+ noEcho
1226
+ };
1227
+ },
1228
+ options?.ackId,
1229
+ options?.abortSignal
1230
+ );
1231
+ }
1232
+ const message = {
1233
+ kind: "sendToGroup",
1234
+ group: groupName,
1235
+ dataType,
1236
+ data: content,
1237
+ noEcho
1238
+ };
1239
+ await this._sendMessage(message, options?.abortSignal);
1240
+ return { isDuplicated: false };
1241
+ }
1242
+ _getWebSocketClientFactory() {
1243
+ return new WebSocketClientFactory();
1244
+ }
1245
+ async _trySendSequenceAck() {
1246
+ if (!this._protocol.isReliableSubProtocol) {
1247
+ return;
1248
+ }
1249
+ const [isUpdated, seqId] = this._sequenceId.tryGetSequenceId();
1250
+ if (isUpdated && seqId !== null && seqId !== void 0) {
1251
+ const message = {
1252
+ kind: "sequenceAck",
1253
+ sequenceId: seqId
1254
+ };
1255
+ try {
1256
+ await this._sendMessage(message);
1257
+ } catch {
1258
+ this._sequenceId.tryUpdate(seqId);
1259
+ }
1260
+ }
1261
+ }
1262
+ _connectCore(uri) {
1263
+ if (this._isStopping) {
1264
+ throw new Error("Can't start a client during stopping");
1265
+ }
1266
+ return new Promise((resolve, reject) => {
1267
+ const client = this._wsClient = this._getWebSocketClientFactory().create(
1268
+ uri,
1269
+ this._protocol.name
1270
+ );
1271
+ client.onopen(() => {
1272
+ if (this._isStopping) {
1273
+ try {
1274
+ client.close();
1275
+ } catch {
1276
+ }
1277
+ reject(new Error(`The client is stopped`));
1278
+ }
1279
+ logger.verbose("WebSocket connection has opened");
1280
+ this._lastMessageReceived = Date.now();
1281
+ this._changeState(
1282
+ "Connected"
1283
+ /* Connected */
1284
+ );
1285
+ if (this._protocol.isReliableSubProtocol) {
1286
+ if (this._sequenceAckTask != null) {
1287
+ this._sequenceAckTask.abort();
1288
+ }
1289
+ this._sequenceAckTask = new AbortableTask(async () => {
1290
+ await this._trySendSequenceAck();
1291
+ }, 1e3);
1292
+ }
1293
+ resolve();
1294
+ });
1295
+ client.onerror((e) => {
1296
+ if (this._sequenceAckTask != null) {
1297
+ this._sequenceAckTask.abort();
1298
+ }
1299
+ reject(e);
1300
+ });
1301
+ client.onclose((code, reason) => {
1302
+ if (this._state === "Connected") {
1303
+ logger.verbose("WebSocket closed after open");
1304
+ if (this._sequenceAckTask != null) {
1305
+ this._sequenceAckTask.abort();
1306
+ }
1307
+ logger.info(`WebSocket connection closed. Code: ${code}, Reason: ${reason}`);
1308
+ this._lastCloseEvent = { code, reason };
1309
+ this._handleConnectionClose.call(this);
1310
+ } else {
1311
+ logger.verbose("WebSocket closed before open");
1312
+ reject(new Error(`Failed to start WebSocket: ${code}`));
1313
+ }
1314
+ });
1315
+ client.onmessage((data) => {
1316
+ const handleAckMessage = (message) => {
1317
+ const isDuplicated = message.error != null && message.error.name === "Duplicate";
1318
+ if (message.success || isDuplicated) {
1319
+ this._ackManager.resolveAck(message.ackId, {
1320
+ ackId: message.ackId,
1321
+ isDuplicated
1322
+ });
1323
+ } else {
1324
+ this._ackManager.rejectAck(
1325
+ message.ackId,
1326
+ new SendMessageError("Failed to send message.", {
1327
+ ackId: message.ackId,
1328
+ errorDetail: message.error
1329
+ })
1330
+ );
1331
+ }
1332
+ };
1333
+ const handleConnectedMessage = async (message) => {
1334
+ this._connectionId = message.connectionId;
1335
+ this._reconnectionToken = message.reconnectionToken;
1336
+ if (!this._isInitialConnected) {
1337
+ this._isInitialConnected = true;
1338
+ if (this._options.autoRejoinGroups) {
1339
+ const groupPromises = [];
1340
+ this._groupMap.forEach((g) => {
1341
+ if (g.isJoined) {
1342
+ groupPromises.push(
1343
+ (async () => {
1344
+ try {
1345
+ await this._joinGroupCore(g.name);
1346
+ } catch (err) {
1347
+ this._safeEmitRejoinGroupFailed(g.name, err);
1348
+ }
1349
+ })()
1350
+ );
1351
+ }
1352
+ });
1353
+ await Promise.all(groupPromises).catch(() => {
1354
+ });
1355
+ }
1356
+ this._safeEmitConnected(message.connectionId, message.userId);
1357
+ }
1358
+ };
1359
+ const handleDisconnectedMessage = (message) => {
1360
+ this._lastDisconnectedMessage = message;
1361
+ };
1362
+ const handleGroupDataMessage = (message) => {
1363
+ if (message.sequenceId != null) {
1364
+ const diff = this._sequenceId.tryUpdate(message.sequenceId);
1365
+ if (diff === 0) {
1366
+ return;
1367
+ }
1368
+ if (diff > this._quickSequenceAckDiff) {
1369
+ this._trySendSequenceAck();
1370
+ }
1371
+ }
1372
+ this._safeEmitGroupMessage(message);
1373
+ };
1374
+ const handleServerDataMessage = (message) => {
1375
+ if (message.sequenceId != null) {
1376
+ const diff = this._sequenceId.tryUpdate(message.sequenceId);
1377
+ if (diff === 0) {
1378
+ return;
1379
+ }
1380
+ if (diff > this._quickSequenceAckDiff) {
1381
+ this._trySendSequenceAck();
1382
+ }
1383
+ }
1384
+ this._safeEmitServerMessage(message);
1385
+ };
1386
+ const handleInvokeResponseMessage = (message) => {
1387
+ const resolved = this._invocationManager.resolveInvocation(message);
1388
+ if (!resolved) {
1389
+ logger.verbose(
1390
+ `Received invokeResponse for unknown invocationId: ${message.invocationId}`
1391
+ );
1392
+ }
1393
+ };
1394
+ this._lastMessageReceived = Date.now();
1395
+ let messages;
1396
+ try {
1397
+ let convertedData;
1398
+ if (Array.isArray(data)) {
1399
+ convertedData = Buffer.concat(data);
1400
+ } else {
1401
+ convertedData = data;
1402
+ }
1403
+ messages = this._protocol.parseMessages(convertedData);
1404
+ if (messages === null) {
1405
+ return;
1406
+ }
1407
+ } catch (err) {
1408
+ logger.warning("An error occurred while parsing the message from service", err);
1409
+ throw err;
1410
+ }
1411
+ if (!Array.isArray(messages)) {
1412
+ messages = [messages];
1413
+ }
1414
+ messages.forEach((message) => {
1415
+ try {
1416
+ switch (message.kind) {
1417
+ case "pong": {
1418
+ break;
1419
+ }
1420
+ case "ack": {
1421
+ handleAckMessage(message);
1422
+ break;
1423
+ }
1424
+ case "connected": {
1425
+ handleConnectedMessage(message);
1426
+ break;
1427
+ }
1428
+ case "disconnected": {
1429
+ handleDisconnectedMessage(message);
1430
+ break;
1431
+ }
1432
+ case "groupData": {
1433
+ handleGroupDataMessage(message);
1434
+ break;
1435
+ }
1436
+ case "serverData": {
1437
+ handleServerDataMessage(message);
1438
+ break;
1439
+ }
1440
+ case "invokeResponse": {
1441
+ handleInvokeResponseMessage(message);
1442
+ break;
1443
+ }
1444
+ }
1445
+ } catch (err) {
1446
+ logger.warning(
1447
+ `An error occurred while handling the message with kind: ${message.kind} from service`,
1448
+ err
1449
+ );
1450
+ }
1451
+ });
1452
+ });
1453
+ });
1454
+ }
1455
+ async _handleConnectionCloseAndNoRecovery() {
1456
+ this._state = "Disconnected";
1457
+ this._safeEmitDisconnected(this._connectionId, this._lastDisconnectedMessage);
1458
+ if (this._options.autoReconnect) {
1459
+ await this._autoReconnect();
1460
+ } else {
1461
+ await this._handleConnectionStopped();
1462
+ }
1463
+ }
1464
+ async _autoReconnect() {
1465
+ let isSuccess = false;
1466
+ let attempt = 0;
1467
+ try {
1468
+ while (!this._isStopping) {
1469
+ try {
1470
+ await this._startFromRestarting();
1471
+ isSuccess = true;
1472
+ break;
1473
+ } catch (err) {
1474
+ logger.warning("An attempt to reconnect connection failed.", err);
1475
+ attempt++;
1476
+ const delayInMs = this._reconnectRetryPolicy.nextRetryDelayInMs(attempt);
1477
+ if (delayInMs == null) {
1478
+ break;
1479
+ }
1480
+ logger.verbose(`Delay time for reconnect attempt ${attempt}: ${delayInMs}`);
1481
+ await delay(delayInMs).catch(() => {
1482
+ });
1483
+ }
1484
+ }
1485
+ } finally {
1486
+ if (!isSuccess) {
1487
+ this._handleConnectionStopped();
1488
+ }
1489
+ }
1490
+ }
1491
+ _handleConnectionStopped() {
1492
+ this._isStopping = false;
1493
+ this._state = "Stopped";
1494
+ this._disposeKeepaliveTasks();
1495
+ this._safeEmitStopped();
1496
+ }
1497
+ async _trySendPing() {
1498
+ if (this._state !== "Connected" || !this._wsClient?.isOpen()) {
1499
+ return;
1500
+ }
1501
+ const message = {
1502
+ kind: "ping"
1503
+ };
1504
+ try {
1505
+ await this._sendMessage(message);
1506
+ } catch {
1507
+ logger.warning("Failed to send keepalive message to the service");
1508
+ }
1509
+ }
1510
+ async _checkKeepAliveTimeout() {
1511
+ if (this._state !== "Connected" || !this._wsClient?.isOpen()) {
1512
+ return;
1513
+ }
1514
+ const now = Date.now();
1515
+ if (now - this._lastMessageReceived > this._keepAliveTimeoutInMs) {
1516
+ logger.warning(
1517
+ `No messages received for ${now - this._lastMessageReceived} ms. Closing. The keep alive timeout is set to ${this._keepAliveTimeoutInMs} ms.`
1518
+ );
1519
+ this._wsClient?.close();
1520
+ }
1521
+ }
1522
+ _getPingKeepaliveTask() {
1523
+ return new AbortableTask(async () => {
1524
+ await this._trySendPing();
1525
+ }, this._keepAliveIntervalInMs);
1526
+ }
1527
+ _getTimeoutMonitorTask() {
1528
+ const timeout = this._keepAliveTimeoutInMs;
1529
+ const checkInterval = Math.floor(timeout / 3);
1530
+ return new AbortableTask(async () => {
1531
+ await this._checkKeepAliveTimeout();
1532
+ }, checkInterval);
1533
+ }
1534
+ async _sendMessage(message, abortSignal) {
1535
+ if (!this._wsClient || !this._wsClient.isOpen()) {
1536
+ throw new Error("The connection is not connected.");
1537
+ }
1538
+ const payload = this._protocol.writeMessage(message);
1539
+ await this._wsClient.send(payload, abortSignal);
1540
+ }
1541
+ async _sendMessageWithAckId(messageProvider, ackId, abortSignal) {
1542
+ const { ackId: resolvedAckId, wait } = this._ackManager.registerAck(ackId);
1543
+ const message = messageProvider(resolvedAckId);
1544
+ try {
1545
+ await this._sendMessage(message, abortSignal);
1546
+ } catch (error) {
1547
+ this._ackManager.discard(resolvedAckId);
1548
+ let errorMessage = "";
1549
+ if (error instanceof Error) {
1550
+ errorMessage = error.message;
1551
+ }
1552
+ throw new SendMessageError(errorMessage, { ackId: resolvedAckId });
1553
+ }
1554
+ return wait(abortSignal);
1555
+ }
1556
+ async _handleConnectionClose() {
1557
+ this._ackManager.rejectAll((ackId) => {
1558
+ return new SendMessageError(
1559
+ "Connection is disconnected before receive ack from the service",
1560
+ {
1561
+ ackId
1562
+ }
1563
+ );
1564
+ });
1565
+ this._invocationManager.rejectAll((invocationId) => {
1566
+ return new InvocationError(
1567
+ "Connection is disconnected before receiving invoke response from the service",
1568
+ {
1569
+ invocationId
1570
+ }
1571
+ );
1572
+ });
1573
+ if (this._isStopping) {
1574
+ logger.warning("The client is stopping state. Stop recovery.");
1575
+ this._handleConnectionCloseAndNoRecovery();
1576
+ return;
1577
+ }
1578
+ if (this._lastCloseEvent && this._lastCloseEvent.code === 1008) {
1579
+ logger.warning("The websocket close with status code 1008. Stop recovery.");
1580
+ this._handleConnectionCloseAndNoRecovery();
1581
+ return;
1582
+ }
1583
+ if (!this._protocol.isReliableSubProtocol) {
1584
+ logger.warning("The protocol is not reliable, recovery is not applicable");
1585
+ this._handleConnectionCloseAndNoRecovery();
1586
+ return;
1587
+ }
1588
+ const recoveryUri = this._buildRecoveryUri();
1589
+ if (!recoveryUri) {
1590
+ logger.warning("Connection id or reconnection token is not available");
1591
+ this._handleConnectionCloseAndNoRecovery();
1592
+ return;
1593
+ }
1594
+ let recovered = false;
1595
+ this._state = "Recovering";
1596
+ const abortSignal = AbortSignal.timeout(30 * 1e3);
1597
+ try {
1598
+ while (!abortSignal.aborted || this._isStopping) {
1599
+ try {
1600
+ await this._connectCore.call(this, recoveryUri);
1601
+ recovered = true;
1602
+ return;
1603
+ } catch {
1604
+ await delay(1e3);
1605
+ }
1606
+ }
1607
+ } finally {
1608
+ if (!recovered) {
1609
+ logger.warning("Recovery attempts failed more then 30 seconds or the client is stopping");
1610
+ this._handleConnectionCloseAndNoRecovery();
1611
+ }
1612
+ }
1613
+ }
1614
+ _safeEmitConnected(connectionId, userId) {
1615
+ this._emitEvent("connected", {
1616
+ connectionId,
1617
+ userId
1618
+ });
1619
+ }
1620
+ _safeEmitDisconnected(connectionId, lastDisconnectedMessage) {
1621
+ this._emitEvent("disconnected", {
1622
+ connectionId,
1623
+ message: lastDisconnectedMessage
1624
+ });
1625
+ }
1626
+ _safeEmitGroupMessage(message) {
1627
+ this._emitEvent("group-message", {
1628
+ message
1629
+ });
1630
+ }
1631
+ _safeEmitServerMessage(message) {
1632
+ this._emitEvent("server-message", {
1633
+ message
1634
+ });
1635
+ }
1636
+ _safeEmitStopped() {
1637
+ this._emitEvent("stopped", {});
1638
+ }
1639
+ _safeEmitRejoinGroupFailed(groupName, err) {
1640
+ this._emitEvent("rejoin-group-failed", {
1641
+ group: groupName,
1642
+ error: err
1643
+ });
1644
+ }
1645
+ _mapInvokeResponse(message) {
1646
+ if (message.success !== true) {
1647
+ if (message.success === false) {
1648
+ throw new InvocationError(message.error?.message ?? "Invocation failed.", {
1649
+ invocationId: message.invocationId,
1650
+ errorDetail: message.error
1651
+ });
1652
+ }
1653
+ throw new InvocationError("Unsupported invoke response frame.", {
1654
+ invocationId: message.invocationId
1655
+ });
1656
+ }
1657
+ return {
1658
+ invocationId: message.invocationId,
1659
+ dataType: message.dataType,
1660
+ data: message.data
1661
+ };
1662
+ }
1663
+ async _sendCancelInvocation(invocationId) {
1664
+ const message = {
1665
+ kind: "cancelInvocation",
1666
+ invocationId
1667
+ };
1668
+ try {
1669
+ await this._sendMessage(message);
1670
+ } catch (err) {
1671
+ logger.verbose(`Failed to send cancelInvocation for ${invocationId}`, err);
1672
+ }
1673
+ }
1674
+ _buildDefaultOptions(clientOptions) {
1675
+ if (clientOptions.autoReconnect == null) {
1676
+ clientOptions.autoReconnect = true;
1677
+ }
1678
+ if (clientOptions.autoRejoinGroups == null) {
1679
+ clientOptions.autoRejoinGroups = true;
1680
+ }
1681
+ if (clientOptions.protocol == null) {
1682
+ clientOptions.protocol = WebPubSubJsonReliableProtocol();
1683
+ }
1684
+ if (clientOptions.keepAliveTimeoutInMs == null) {
1685
+ clientOptions.keepAliveTimeoutInMs = 12e4;
1686
+ }
1687
+ if (clientOptions.keepAliveTimeoutInMs < 0) {
1688
+ throw new RangeError("keepAliveTimeoutInMs must be greater than or equal to 0.");
1689
+ }
1690
+ if (clientOptions.keepAliveIntervalInMs == null) {
1691
+ clientOptions.keepAliveIntervalInMs = 2e4;
1692
+ }
1693
+ if (clientOptions.keepAliveIntervalInMs < 0) {
1694
+ throw new RangeError("keepAliveIntervalInMs must be greater than or equal to 0.");
1695
+ }
1696
+ this._buildMessageRetryOptions(clientOptions);
1697
+ this._buildReconnectRetryOptions(clientOptions);
1698
+ return clientOptions;
1699
+ }
1700
+ _buildMessageRetryOptions(clientOptions) {
1701
+ if (!clientOptions.messageRetryOptions) {
1702
+ clientOptions.messageRetryOptions = {};
1703
+ }
1704
+ if (clientOptions.messageRetryOptions.maxRetries == null || clientOptions.messageRetryOptions.maxRetries < 0) {
1705
+ clientOptions.messageRetryOptions.maxRetries = 3;
1706
+ }
1707
+ if (clientOptions.messageRetryOptions.retryDelayInMs == null || clientOptions.messageRetryOptions.retryDelayInMs < 0) {
1708
+ clientOptions.messageRetryOptions.retryDelayInMs = 1e3;
1709
+ }
1710
+ if (clientOptions.messageRetryOptions.maxRetryDelayInMs == null || clientOptions.messageRetryOptions.maxRetryDelayInMs < 0) {
1711
+ clientOptions.messageRetryOptions.maxRetryDelayInMs = 3e4;
1712
+ }
1713
+ if (clientOptions.messageRetryOptions.mode == null) {
1714
+ clientOptions.messageRetryOptions.mode = "Fixed";
1715
+ }
1716
+ }
1717
+ _buildReconnectRetryOptions(clientOptions) {
1718
+ if (!clientOptions.reconnectRetryOptions) {
1719
+ clientOptions.reconnectRetryOptions = {};
1720
+ }
1721
+ if (clientOptions.reconnectRetryOptions.maxRetries == null || clientOptions.reconnectRetryOptions.maxRetries < 0) {
1722
+ clientOptions.reconnectRetryOptions.maxRetries = Number.MAX_VALUE;
1723
+ }
1724
+ if (clientOptions.reconnectRetryOptions.retryDelayInMs == null || clientOptions.reconnectRetryOptions.retryDelayInMs < 0) {
1725
+ clientOptions.reconnectRetryOptions.retryDelayInMs = 1e3;
1726
+ }
1727
+ if (clientOptions.reconnectRetryOptions.maxRetryDelayInMs == null || clientOptions.reconnectRetryOptions.maxRetryDelayInMs < 0) {
1728
+ clientOptions.reconnectRetryOptions.maxRetryDelayInMs = 3e4;
1729
+ }
1730
+ if (clientOptions.reconnectRetryOptions.mode == null) {
1731
+ clientOptions.reconnectRetryOptions.mode = "Fixed";
1732
+ }
1733
+ }
1734
+ _buildRecoveryUri() {
1735
+ if (this._connectionId && this._reconnectionToken && this._uri) {
1736
+ const url = new URL(this._uri);
1737
+ url.searchParams.append("awps_connection_id", this._connectionId);
1738
+ url.searchParams.append("awps_reconnection_token", this._reconnectionToken);
1739
+ return url.toString();
1740
+ }
1741
+ return null;
1742
+ }
1743
+ _getOrAddGroup(name) {
1744
+ if (!this._groupMap.has(name)) {
1745
+ this._groupMap.set(name, new WebPubSubGroup(name));
1746
+ }
1747
+ return this._groupMap.get(name);
1748
+ }
1749
+ _changeState(newState) {
1750
+ logger.verbose(
1751
+ `The client state transfer from ${this._state.toString()} to ${newState.toString()}`
1752
+ );
1753
+ this._state = newState;
1754
+ }
1755
+ async _operationExecuteWithRetry(inner, signal) {
1756
+ let retryAttempt = 0;
1757
+ while (true) {
1758
+ try {
1759
+ return await inner.call(this);
1760
+ } catch (err) {
1761
+ if (err instanceof InvocationError) {
1762
+ throw err;
1763
+ }
1764
+ retryAttempt++;
1765
+ const delayInMs = this._messageRetryPolicy.nextRetryDelayInMs(retryAttempt);
1766
+ if (delayInMs == null) {
1767
+ throw err;
1768
+ }
1769
+ await delay(delayInMs);
1770
+ if (signal?.aborted) {
1771
+ throw err;
1772
+ }
1773
+ }
1774
+ }
1775
+ }
1776
+ };
1777
+ var RetryPolicy = class {
1778
+ constructor(retryOptions) {
1779
+ __publicField(this, "_retryOptions");
1780
+ __publicField(this, "_maxRetriesToGetMaxDelay");
1781
+ this._retryOptions = retryOptions;
1782
+ this._maxRetriesToGetMaxDelay = Math.ceil(
1783
+ Math.log2(this._retryOptions.maxRetryDelayInMs) - Math.log2(this._retryOptions.retryDelayInMs) + 1
1784
+ );
1785
+ }
1786
+ nextRetryDelayInMs(retryAttempt) {
1787
+ if (retryAttempt > this._retryOptions.maxRetries) {
1788
+ return null;
1789
+ } else {
1790
+ if (this._retryOptions.mode === "Fixed") {
1791
+ return this._retryOptions.retryDelayInMs;
1792
+ } else {
1793
+ return this._calculateExponentialDelay(retryAttempt);
1794
+ }
1795
+ }
1796
+ }
1797
+ _calculateExponentialDelay(attempt) {
1798
+ if (attempt >= this._maxRetriesToGetMaxDelay) {
1799
+ return this._retryOptions.maxRetryDelayInMs;
1800
+ } else {
1801
+ return (1 << attempt - 1) * this._retryOptions.retryDelayInMs;
1802
+ }
1803
+ }
1804
+ };
1805
+ var WebPubSubGroup = class {
1806
+ constructor(name) {
1807
+ __publicField(this, "name");
1808
+ __publicField(this, "isJoined", false);
1809
+ this.name = name;
1810
+ }
1811
+ };
1812
+ var SequenceId = class {
1813
+ constructor() {
1814
+ __publicField(this, "_sequenceId");
1815
+ __publicField(this, "_isUpdate");
1816
+ this._sequenceId = 0;
1817
+ this._isUpdate = false;
1818
+ }
1819
+ tryUpdate(sequenceId) {
1820
+ this._isUpdate = true;
1821
+ if (sequenceId > this._sequenceId) {
1822
+ const diff = sequenceId - this._sequenceId;
1823
+ this._sequenceId = sequenceId;
1824
+ return diff;
1825
+ }
1826
+ return 0;
1827
+ }
1828
+ tryGetSequenceId() {
1829
+ if (this._isUpdate) {
1830
+ this._isUpdate = false;
1831
+ return [true, this._sequenceId];
1832
+ }
1833
+ return [false, null];
1834
+ }
1835
+ reset() {
1836
+ this._sequenceId = 0;
1837
+ this._isUpdate = false;
1838
+ }
1839
+ };
1840
+ var AbortableTask = class {
1841
+ constructor(func, interval, obj) {
1842
+ __publicField(this, "_func");
1843
+ __publicField(this, "_abortController");
1844
+ __publicField(this, "_interval");
1845
+ __publicField(this, "_obj");
1846
+ this._func = func;
1847
+ this._abortController = new AbortController();
1848
+ this._interval = interval;
1849
+ this._obj = obj;
1850
+ this._start();
1851
+ }
1852
+ abort() {
1853
+ try {
1854
+ this._abortController.abort();
1855
+ } catch {
1856
+ }
1857
+ }
1858
+ async _start() {
1859
+ const signal = this._abortController.signal;
1860
+ while (!signal.aborted) {
1861
+ try {
1862
+ await this._func(this._obj);
1863
+ } catch {
1864
+ } finally {
1865
+ await delay(this._interval);
1866
+ }
1867
+ }
1868
+ }
1869
+ };
1870
+
1871
+ // node_modules/tslib/tslib.es6.mjs
1872
+ function __values(o) {
1873
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
1874
+ if (m) return m.call(o);
1875
+ if (o && typeof o.length === "number") return {
1876
+ next: function() {
1877
+ if (o && i >= o.length) o = void 0;
1878
+ return { value: o && o[i++], done: !o };
1879
+ }
1880
+ };
1881
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
1882
+ }
1883
+ function __await(v) {
1884
+ return this instanceof __await ? (this.v = v, this) : new __await(v);
1885
+ }
1886
+ function __asyncGenerator(thisArg, _arguments, generator) {
1887
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1888
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
1889
+ return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
1890
+ return this;
1891
+ }, i;
1892
+ function awaitReturn(f) {
1893
+ return function(v) {
1894
+ return Promise.resolve(v).then(f, reject);
1895
+ };
1896
+ }
1897
+ function verb(n, f) {
1898
+ if (g[n]) {
1899
+ i[n] = function(v) {
1900
+ return new Promise(function(a, b) {
1901
+ q.push([n, v, a, b]) > 1 || resume(n, v);
1902
+ });
1903
+ };
1904
+ if (f) i[n] = f(i[n]);
1905
+ }
1906
+ }
1907
+ function resume(n, v) {
1908
+ try {
1909
+ step(g[n](v));
1910
+ } catch (e) {
1911
+ settle(q[0][3], e);
1912
+ }
1913
+ }
1914
+ function step(r) {
1915
+ r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
1916
+ }
1917
+ function fulfill(value) {
1918
+ resume("next", value);
1919
+ }
1920
+ function reject(value) {
1921
+ resume("throw", value);
1922
+ }
1923
+ function settle(f, v) {
1924
+ if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
1925
+ }
1926
+ }
1927
+ function __asyncDelegator(o) {
1928
+ var i, p;
1929
+ return i = {}, verb("next"), verb("throw", function(e) {
1930
+ throw e;
1931
+ }), verb("return"), i[Symbol.iterator] = function() {
1932
+ return this;
1933
+ }, i;
1934
+ function verb(n, f) {
1935
+ i[n] = o[n] ? function(v) {
1936
+ return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v;
1937
+ } : f;
1938
+ }
1939
+ }
1940
+ function __asyncValues(o) {
1941
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
1942
+ var m = o[Symbol.asyncIterator], i;
1943
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
1944
+ return this;
1945
+ }, i);
1946
+ function verb(n) {
1947
+ i[n] = o[n] && function(v) {
1948
+ return new Promise(function(resolve, reject) {
1949
+ v = o[n](v), settle(resolve, reject, v.done, v.value);
1950
+ });
1951
+ };
1952
+ }
1953
+ function settle(resolve, reject, d, v) {
1954
+ Promise.resolve(v).then(function(v2) {
1955
+ resolve({ value: v2, done: d });
1956
+ }, reject);
1957
+ }
1958
+ }
1959
+
1960
+ // node_modules/@azure/core-paging/dist/esm/getPagedAsyncIterator.js
1961
+ function getPagedAsyncIterator(pagedResult) {
1962
+ var _a;
1963
+ const iter = getItemAsyncIterator(pagedResult);
1964
+ return {
1965
+ next() {
1966
+ return iter.next();
1967
+ },
1968
+ [Symbol.asyncIterator]() {
1969
+ return this;
1970
+ },
1971
+ byPage: (_a = pagedResult === null || pagedResult === void 0 ? void 0 : pagedResult.byPage) !== null && _a !== void 0 ? _a : ((settings) => {
1972
+ const { continuationToken, maxPageSize } = settings !== null && settings !== void 0 ? settings : {};
1973
+ return getPageAsyncIterator(pagedResult, {
1974
+ pageLink: continuationToken,
1975
+ maxPageSize
1976
+ });
1977
+ })
1978
+ };
1979
+ }
1980
+ function getItemAsyncIterator(pagedResult) {
1981
+ return __asyncGenerator(this, arguments, function* getItemAsyncIterator_1() {
1982
+ var _a, e_1, _b, _c, _d, e_2, _e, _f;
1983
+ const pages = getPageAsyncIterator(pagedResult);
1984
+ const firstVal = yield __await(pages.next());
1985
+ if (!Array.isArray(firstVal.value)) {
1986
+ const { toElements } = pagedResult;
1987
+ if (toElements) {
1988
+ yield __await(yield* __asyncDelegator(__asyncValues(toElements(firstVal.value))));
1989
+ try {
1990
+ for (var _g = true, pages_1 = __asyncValues(pages), pages_1_1; pages_1_1 = yield __await(pages_1.next()), _a = pages_1_1.done, !_a; _g = true) {
1991
+ _c = pages_1_1.value;
1992
+ _g = false;
1993
+ const page = _c;
1994
+ yield __await(yield* __asyncDelegator(__asyncValues(toElements(page))));
1995
+ }
1996
+ } catch (e_1_1) {
1997
+ e_1 = { error: e_1_1 };
1998
+ } finally {
1999
+ try {
2000
+ if (!_g && !_a && (_b = pages_1.return)) yield __await(_b.call(pages_1));
2001
+ } finally {
2002
+ if (e_1) throw e_1.error;
2003
+ }
2004
+ }
2005
+ } else {
2006
+ yield yield __await(firstVal.value);
2007
+ yield __await(yield* __asyncDelegator(__asyncValues(pages)));
2008
+ }
2009
+ } else {
2010
+ yield __await(yield* __asyncDelegator(__asyncValues(firstVal.value)));
2011
+ try {
2012
+ for (var _h = true, pages_2 = __asyncValues(pages), pages_2_1; pages_2_1 = yield __await(pages_2.next()), _d = pages_2_1.done, !_d; _h = true) {
2013
+ _f = pages_2_1.value;
2014
+ _h = false;
2015
+ const page = _f;
2016
+ yield __await(yield* __asyncDelegator(__asyncValues(page)));
2017
+ }
2018
+ } catch (e_2_1) {
2019
+ e_2 = { error: e_2_1 };
2020
+ } finally {
2021
+ try {
2022
+ if (!_h && !_d && (_e = pages_2.return)) yield __await(_e.call(pages_2));
2023
+ } finally {
2024
+ if (e_2) throw e_2.error;
2025
+ }
2026
+ }
2027
+ }
2028
+ });
2029
+ }
2030
+ function getPageAsyncIterator(pagedResult, options = {}) {
2031
+ return __asyncGenerator(this, arguments, function* getPageAsyncIterator_1() {
2032
+ const { pageLink, maxPageSize } = options;
2033
+ let response = yield __await(pagedResult.getPage(pageLink !== null && pageLink !== void 0 ? pageLink : pagedResult.firstPageLink, maxPageSize));
2034
+ if (!response) {
2035
+ return yield __await(void 0);
2036
+ }
2037
+ yield yield __await(response.page);
2038
+ while (response.nextPageLink) {
2039
+ response = yield __await(pagedResult.getPage(response.nextPageLink, maxPageSize));
2040
+ if (!response) {
2041
+ return yield __await(void 0);
2042
+ }
2043
+ yield yield __await(response.page);
2044
+ }
2045
+ });
2046
+ }
2047
+
2048
+ // src/chatClient.ts
2049
+ import { EventEmitter as EventEmitter2 } from "events";
2050
+
2051
+ // src/constant.ts
2052
+ var INVOCATION_NAME = {
2053
+ LOGIN: "chat.login",
2054
+ LIST_USER_CONVERSATION: "chat.listUserConversation",
2055
+ GET_USER_PROPERTIES: "chat.getUserProperties",
2056
+ GET_ROOM: "chat.getRoom",
2057
+ LIST_MESSAGES: "chat.queryMessageHistory",
2058
+ SEND_TEXT_MESSAGE: "chat.sendTextMessage",
2059
+ CREATE_ROOM: "chat.createRoom",
2060
+ JOIN_ROOM: "chat.joinRoom",
2061
+ MANAGE_ROOM_MEMBER: "chat.manageRoomMember"
2062
+ };
2063
+ var ERRORS = {
2064
+ RoomAlreadyExists: "RoomAlreadyExists",
2065
+ UserAlreadyInRoom: "UserAlreadyInRoom",
2066
+ NoPermissionInRoom: "NoPermissionInRoom",
2067
+ NotStarted: "NotStarted",
2068
+ UnknownRoom: "UnknownRoom",
2069
+ InvalidServerResponse: "InvalidServerResponse"
2070
+ };
2071
+
2072
+ // src/logger.ts
2073
+ var logger2 = createClientLogger("web-pubsub-chat-client:*");
2074
+
2075
+ // src/utils.ts
2076
+ function isWebPubSubClient(obj) {
2077
+ if (typeof obj !== "object" || obj === null) return false;
2078
+ const anyObj = obj;
2079
+ return typeof anyObj === "object" && (typeof anyObj.start === "function" || typeof anyObj.stop === "function" || typeof anyObj.on === "function");
2080
+ }
2081
+
2082
+ // src/chatClient.ts
2083
+ var ChatError = class extends Error {
2084
+ constructor(message, code) {
2085
+ super(message);
2086
+ /** Stable, machine-readable error code. Compare against {@link KnownChatErrorCode}. */
2087
+ __publicField(this, "code");
2088
+ this.name = "ChatError";
2089
+ this.code = code;
2090
+ }
2091
+ };
2092
+ var PromiseCompletionSource = class {
2093
+ constructor() {
2094
+ __publicField(this, "promise");
2095
+ __publicField(this, "resolvePromise");
2096
+ this.promise = new Promise((resolve) => {
2097
+ this.resolvePromise = resolve;
2098
+ });
2099
+ }
2100
+ setResult() {
2101
+ this.resolvePromise();
2102
+ }
2103
+ wait() {
2104
+ return this.promise;
2105
+ }
2106
+ };
2107
+ var ChatClient = class _ChatClient {
2108
+ // Implementation also accepts a pre-built connection (test seam); this is
2109
+ // not a public overload, so it does not appear in the public API surface.
2110
+ constructor(credentialOrConnection) {
2111
+ /** The underlying transport. Private — `ChatClient` builds and owns it. */
2112
+ __publicField(this, "_connection");
2113
+ __publicField(this, "_emitter", new EventEmitter2());
2114
+ __publicField(this, "_rooms", /* @__PURE__ */ new Map());
2115
+ __publicField(this, "_conversationIds", /* @__PURE__ */ new Set());
2116
+ __publicField(this, "_userId");
2117
+ __publicField(this, "_isStarted", false);
2118
+ __publicField(this, "_startPromise");
2119
+ // Created after the underlying connection starts so stop() can wait for the single "stopped" event.
2120
+ __publicField(this, "_connectionStoppedTCS");
2121
+ __publicField(this, "_isConnectionStopping", false);
2122
+ this._connection = isWebPubSubClient(credentialOrConnection) ? credentialOrConnection : new WebPubSubClient(credentialOrConnection);
2123
+ this._connection.on("group-message", (e) => {
2124
+ this._handleNotification(e.message.data);
2125
+ });
2126
+ this._connection.on("server-message", (e) => {
2127
+ this._handleNotification(e.message.data);
2128
+ });
2129
+ this._connection.on("stopped", () => {
2130
+ this._connectionStoppedTCS?.setResult();
2131
+ this._connectionStoppedTCS = void 0;
2132
+ this._isConnectionStopping = false;
2133
+ this.resetState();
2134
+ });
2135
+ }
2136
+ async _handleNotification(data) {
2137
+ if (!this._isStarted && !this._startPromise) {
2138
+ return;
2139
+ }
2140
+ logger2.info("Received notification:", data);
2141
+ try {
2142
+ const type = data.notificationType;
2143
+ switch (type) {
2144
+ case "MessageCreated": {
2145
+ const body = data.body;
2146
+ if (!body.conversation.roomId) {
2147
+ logger2.warning(
2148
+ `MessageCreated notification missing roomId; skipping emit. conversationId=${body.conversation.conversationId}`
2149
+ );
2150
+ break;
2151
+ }
2152
+ const event = {
2153
+ roomId: body.conversation.roomId,
2154
+ message: body.message
2155
+ };
2156
+ this._emitter.emit("message", event);
2157
+ break;
2158
+ }
2159
+ case "RoomJoined": {
2160
+ const roomInfo = data.body;
2161
+ this._rooms.set(roomInfo.roomId, roomInfo);
2162
+ const event = { room: roomInfo };
2163
+ this._emitter.emit("room-joined", event);
2164
+ break;
2165
+ }
2166
+ case "RoomMemberJoined": {
2167
+ const body = data.body;
2168
+ const event = { roomId: body.roomId, title: body.title, userId: body.userId };
2169
+ this._emitter.emit("member-joined", event);
2170
+ break;
2171
+ }
2172
+ // someone (not self) left a specific room
2173
+ case "RoomMemberLeft": {
2174
+ const body = data.body;
2175
+ const event = { roomId: body.roomId, title: body.title, userId: body.userId };
2176
+ this._emitter.emit("member-left", event);
2177
+ break;
2178
+ }
2179
+ // self left a specific room
2180
+ case "RoomLeft": {
2181
+ const body = data.body;
2182
+ if (!this._rooms.has(body.roomId)) {
2183
+ break;
2184
+ }
2185
+ const event = { roomId: body.roomId, title: body.title };
2186
+ this._emitter.emit("room-left", event);
2187
+ this._rooms.delete(body.roomId);
2188
+ break;
2189
+ }
2190
+ case "MessageUpdated":
2191
+ case "MessageDeleted":
2192
+ case "RoomClosed":
2193
+ case "AddContact":
2194
+ logger2.warning(`Known notification type ${type} received but not implemented yet.`);
2195
+ break;
2196
+ default:
2197
+ logger2.warning(`Unknown notification type received: ${type}`);
2198
+ }
2199
+ } catch (err) {
2200
+ logger2.error(`Error processing notification, error = ${err}, data: `, data);
2201
+ }
2202
+ }
2203
+ /** Invoke server event and return typed data */
2204
+ async invokeWithReturnType(eventName, payload, dataType, options) {
2205
+ logger2.verbose(`invoke event: '${eventName}', dataType: ${dataType}, payload:`, payload);
2206
+ try {
2207
+ const rawResponse = await this._connection.invokeEvent(eventName, payload, dataType, {
2208
+ abortSignal: options?.abortSignal
2209
+ });
2210
+ logger2.verbose(`invoke response for '${eventName}':`, rawResponse);
2211
+ const data = rawResponse.data;
2212
+ if (data && typeof data === "object" && typeof data.code === "string") {
2213
+ throw new ChatError(`Invocation of event "${eventName}" failed: ${data.code}`, data.code);
2214
+ }
2215
+ return data;
2216
+ } catch (e) {
2217
+ if (e instanceof ChatError) throw e;
2218
+ if (e instanceof InvocationError && e.errorDetail?.name) {
2219
+ throw new ChatError(e.message, e.errorDetail.name);
2220
+ }
2221
+ throw e;
2222
+ }
2223
+ }
2224
+ static async start(clientAccessUrlOrCredential, options) {
2225
+ const credential = typeof clientAccessUrlOrCredential === "string" ? { getClientAccessUrl: async () => clientAccessUrlOrCredential } : clientAccessUrlOrCredential;
2226
+ const chatClient = new _ChatClient(credential);
2227
+ await chatClient.start({ abortSignal: options?.abortSignal });
2228
+ return chatClient;
2229
+ }
2230
+ /**
2231
+ * Connect the underlying transport and authenticate with the chat
2232
+ * service.
2233
+ *
2234
+ * Idempotent: concurrent calls share a single in-flight promise, and
2235
+ * calls made on an already-started client resolve immediately. After
2236
+ * `stop()` the client can be started again; state from the previous
2237
+ * session is reset.
2238
+ *
2239
+ * @param options - Cancellation token for the start operation. Aborting
2240
+ * leaves the client in its initial (not-started) state.
2241
+ */
2242
+ async start(options) {
2243
+ if (this._startPromise) return this._startPromise;
2244
+ if (this._isStarted) return;
2245
+ if (this._connectionStoppedTCS && this._isConnectionStopping) {
2246
+ await this._connectionStoppedTCS.wait();
2247
+ if (this._startPromise) return this._startPromise;
2248
+ if (this._isStarted) return;
2249
+ }
2250
+ const startPromise = this.startCore(options);
2251
+ this._startPromise = startPromise;
2252
+ try {
2253
+ await startPromise;
2254
+ } finally {
2255
+ if (this._startPromise === startPromise) {
2256
+ this._startPromise = void 0;
2257
+ }
2258
+ }
2259
+ }
2260
+ async startCore(options) {
2261
+ this.resetState();
2262
+ try {
2263
+ await this._connection.start({ abortSignal: options?.abortSignal });
2264
+ this._connectionStoppedTCS = new PromiseCompletionSource();
2265
+ this._isConnectionStopping = false;
2266
+ const loginResponse = await this.invokeWithReturnType(
2267
+ INVOCATION_NAME.LOGIN,
2268
+ "",
2269
+ "text",
2270
+ options
2271
+ );
2272
+ logger2.info("loginResponse", loginResponse);
2273
+ const conversationIds = new Set(loginResponse.conversationIds || []);
2274
+ const roomInfos = await Promise.all(
2275
+ (loginResponse.roomIds || []).map(async (roomId) => {
2276
+ const roomInfo = await this.fetchRoomDetail(roomId, {
2277
+ abortSignal: options?.abortSignal,
2278
+ withMembers: false
2279
+ });
2280
+ return { roomId, roomInfo };
2281
+ })
2282
+ );
2283
+ this._userId = loginResponse.userId;
2284
+ this._conversationIds = conversationIds;
2285
+ roomInfos.forEach(({ roomId, roomInfo }) => {
2286
+ this._rooms.set(roomId, roomInfo);
2287
+ });
2288
+ this._isStarted = true;
2289
+ const startedEvent = { userId: loginResponse.userId };
2290
+ this._emitter.emit("started", startedEvent);
2291
+ } catch (err) {
2292
+ this.resetState();
2293
+ await this.stopConnection();
2294
+ throw err;
2295
+ }
2296
+ }
2297
+ ensureStarted() {
2298
+ if (!this._isStarted) {
2299
+ throw new ChatError("Not started. Please call start() first.", ERRORS.NotStarted);
2300
+ }
2301
+ }
2302
+ /**
2303
+ * Fetch a user's profile.
2304
+ *
2305
+ * @param userId - Id of the user to look up.
2306
+ * @param options - Optional `{ abortSignal }`.
2307
+ */
2308
+ async getUserProfile(userId, options) {
2309
+ this.ensureStarted();
2310
+ return this.invokeWithReturnType(
2311
+ INVOCATION_NAME.GET_USER_PROPERTIES,
2312
+ { userId },
2313
+ "json",
2314
+ options
2315
+ );
2316
+ }
2317
+ async sendToConversation(conversationId, message, options) {
2318
+ this.ensureStarted();
2319
+ const payload = {
2320
+ conversation: { conversationId },
2321
+ content: message
2322
+ };
2323
+ const resp = await this.invokeWithReturnType(
2324
+ INVOCATION_NAME.SEND_TEXT_MESSAGE,
2325
+ payload,
2326
+ "json",
2327
+ options
2328
+ );
2329
+ if (!resp || !resp.id) {
2330
+ throw new ChatError(
2331
+ `Failed to send message to conversation ${conversationId}, got invalid invoke response: ${JSON.stringify(resp)}`,
2332
+ ERRORS.InvalidServerResponse
2333
+ );
2334
+ }
2335
+ const msgId = resp.id;
2336
+ const roomId = Array.from(this._rooms.values()).find((r) => r.defaultConversationId === conversationId)?.roomId;
2337
+ if (!roomId) {
2338
+ logger2.warning(
2339
+ `Failed to find roomId for conversationId ${conversationId} when sending message; skipping local sender-echo emit.`
2340
+ );
2341
+ return { messageId: msgId };
2342
+ }
2343
+ const event = {
2344
+ roomId,
2345
+ message: {
2346
+ messageId: msgId,
2347
+ createdBy: this.userId,
2348
+ messageBodyType: "Inline",
2349
+ content: {
2350
+ text: message,
2351
+ binary: null
2352
+ }
2353
+ }
2354
+ };
2355
+ this._emitter.emit("message", event);
2356
+ return { messageId: msgId };
2357
+ }
2358
+ /**
2359
+ * Send a text message to a room and return the service-assigned message id.
2360
+ *
2361
+ * The room must be one this client has created or joined. The sender also
2362
+ * observes the message through the `"message"` event.
2363
+ *
2364
+ * @param roomId - Target room.
2365
+ * @param message - Message text to send.
2366
+ * @param options - Optional `{ abortSignal }`.
2367
+ * @returns A {@link SendMessageResult} with the service-assigned `messageId`.
2368
+ */
2369
+ async sendToRoom(roomId, message, options) {
2370
+ this.ensureStarted();
2371
+ const conversationId = this._rooms.get(roomId)?.defaultConversationId;
2372
+ if (!conversationId) {
2373
+ throw new ChatError(`Failed to sendToRoom, not found roomId ${roomId}`, ERRORS.UnknownRoom);
2374
+ }
2375
+ return await this.sendToConversation(conversationId, message, options);
2376
+ }
2377
+ // Internal: fetch a room's full wire shape (including its conversation id)
2378
+ // to populate the local cache. Public callers go through getRoomDetail().
2379
+ async fetchRoomDetail(roomId, options) {
2380
+ return this.invokeWithReturnType(
2381
+ INVOCATION_NAME.GET_ROOM,
2382
+ { id: roomId, withMembers: options?.withMembers ?? false },
2383
+ "json",
2384
+ options
2385
+ );
2386
+ }
2387
+ /**
2388
+ * Fetch the detailed view of a room.
2389
+ *
2390
+ * @param roomId - Room to query.
2391
+ * @param options - Optional `{ withMembers, abortSignal }`. Pass
2392
+ * `withMembers: true` to populate the returned `members` list; it is
2393
+ * left undefined otherwise.
2394
+ */
2395
+ async getRoomDetail(roomId, options) {
2396
+ this.ensureStarted();
2397
+ return this.fetchRoomDetail(roomId, options);
2398
+ }
2399
+ /**
2400
+ * Create a room and its initial members. The current user is always
2401
+ * included in the resulting member list.
2402
+ *
2403
+ * @param title - Display title for the room.
2404
+ * @param members - Other user ids to invite. The caller is added
2405
+ * automatically; duplicates are de-duplicated.
2406
+ * @param options - Optional `{ roomId, abortSignal }`. Pass `roomId`
2407
+ * to choose an id explicitly; omit to let the service assign one.
2408
+ */
2409
+ async createRoom(title, members, options) {
2410
+ this.ensureStarted();
2411
+ let roomDetails = {
2412
+ title,
2413
+ members: [.../* @__PURE__ */ new Set([...members, this.userId])]
2414
+ // deduplicate and add self
2415
+ };
2416
+ if (options?.roomId) {
2417
+ roomDetails = { ...roomDetails, roomId: options.roomId };
2418
+ }
2419
+ const roomInfo = await this.invokeWithReturnType(
2420
+ INVOCATION_NAME.CREATE_ROOM,
2421
+ roomDetails,
2422
+ "json",
2423
+ options
2424
+ );
2425
+ this._rooms.set(roomInfo.roomId, roomInfo);
2426
+ const event = { room: roomInfo };
2427
+ this._emitter.emit("room-joined", event);
2428
+ return roomInfo;
2429
+ }
2430
+ async manageRoomMember(request, options) {
2431
+ await this.invokeWithReturnType(INVOCATION_NAME.MANAGE_ROOM_MEMBER, request, "json", options);
2432
+ }
2433
+ async ensureRoomCached(roomId, options) {
2434
+ if (this._rooms.has(roomId)) {
2435
+ return;
2436
+ }
2437
+ const roomInfo = await this.fetchRoomDetail(roomId, options);
2438
+ this._rooms.set(roomId, roomInfo);
2439
+ }
2440
+ /** Add a user to a room. This is an admin operation where one user adds another user to a room. */
2441
+ async addUserToRoom(roomId, userId, options) {
2442
+ this.ensureStarted();
2443
+ const payload = { roomId, operation: "Add", userId };
2444
+ const isSelf = userId === this.userId;
2445
+ const shouldCacheRoomAfterSelfAdd = isSelf && !this._rooms.has(roomId);
2446
+ try {
2447
+ await this.manageRoomMember(payload, options);
2448
+ } catch (error) {
2449
+ if (!isSelf || !(error instanceof ChatError && error.code === ERRORS.UserAlreadyInRoom)) {
2450
+ throw error;
2451
+ }
2452
+ }
2453
+ if (shouldCacheRoomAfterSelfAdd) {
2454
+ await this.ensureRoomCached(roomId, options);
2455
+ }
2456
+ }
2457
+ /** Remove a user from a room. This is an admin operation where one user removes another user from a room. */
2458
+ async removeUserFromRoom(roomId, userId, options) {
2459
+ this.ensureStarted();
2460
+ const payload = { roomId, operation: "Delete", userId };
2461
+ await this.manageRoomMember(payload, options);
2462
+ if (userId === this.userId) {
2463
+ const roomInfo = this._rooms.get(roomId);
2464
+ if (roomInfo) {
2465
+ this._rooms.delete(roomId);
2466
+ const event = { roomId, title: roomInfo.title };
2467
+ this._emitter.emit("room-left", event);
2468
+ }
2469
+ }
2470
+ }
2471
+ /**
2472
+ * List messages in a room as a paged async iterator.
2473
+ *
2474
+ * The iterator transparently fetches additional pages from the
2475
+ * service as you iterate. For Teams-style infinite scrolling, drive
2476
+ * the iterator one page at a time via `byPage(...)`:
2477
+ *
2478
+ * @example Stream every message (e.g. for export or full sync):
2479
+ * ```ts
2480
+ * for await (const msg of client.listRoomMessages(roomId)) {
2481
+ * console.log(msg.content.text);
2482
+ * }
2483
+ * ```
2484
+ *
2485
+ * @example Load history one page at a time (Teams-style scroll-back):
2486
+ * ```ts
2487
+ * // Load up to 50 messages per page.
2488
+ * const pages = client.listRoomMessages(roomId).byPage({ maxPageSize: 50 });
2489
+ * const first = await pages.next();
2490
+ * displayMessages(first.value);
2491
+ * // later, when the user scrolls up:
2492
+ * const more = await pages.next();
2493
+ * displayMessages(more.value);
2494
+ * ```
2495
+ *
2496
+ * The room must be one this client has created or joined.
2497
+ */
2498
+ listRoomMessages(roomId, options) {
2499
+ this.ensureStarted();
2500
+ const conversationId = this._rooms.get(roomId)?.defaultConversationId;
2501
+ if (!conversationId) {
2502
+ throw new ChatError(`Failed to listRoomMessages, not found roomId ${roomId}`, ERRORS.UnknownRoom);
2503
+ }
2504
+ const defaultPageSize = options?.maxPageSize ?? 100;
2505
+ const firstPageLink = {
2506
+ conversation: { conversationId },
2507
+ start: options?.startId ?? null,
2508
+ end: options?.endId ?? null,
2509
+ maxCount: defaultPageSize
2510
+ };
2511
+ const fetchPage = async (link, maxPageSize) => {
2512
+ const query = {
2513
+ ...link,
2514
+ maxCount: maxPageSize ?? link.maxCount ?? defaultPageSize
2515
+ };
2516
+ const result = await this.invokeWithReturnType(
2517
+ INVOCATION_NAME.LIST_MESSAGES,
2518
+ query,
2519
+ "json",
2520
+ { abortSignal: options?.abortSignal }
2521
+ );
2522
+ if (result.messages.length === 0) {
2523
+ return void 0;
2524
+ }
2525
+ return { page: result.messages, nextPageLink: result.nextQuery ?? void 0 };
2526
+ };
2527
+ return getPagedAsyncIterator({
2528
+ firstPageLink,
2529
+ getPage: (link, maxPageSize) => fetchPage(link, maxPageSize)
2530
+ });
2531
+ }
2532
+ /** Cached rooms known to the client. */
2533
+ get rooms() {
2534
+ return Array.from(this._rooms.values());
2535
+ }
2536
+ /** Whether the current client has the room in its local joined-room cache. */
2537
+ hasJoinedRoom(roomId) {
2538
+ return this._rooms.has(roomId);
2539
+ }
2540
+ /**
2541
+ * The chat-domain identity of this client, established by `start()`.
2542
+ *
2543
+ * @throws `ChatError` with code `NotStarted` if the client is not started.
2544
+ */
2545
+ get userId() {
2546
+ if (!this._userId) {
2547
+ throw new ChatError("User ID is not set. Please call start() first.", ERRORS.NotStarted);
2548
+ }
2549
+ return this._userId;
2550
+ }
2551
+ on(event, listener) {
2552
+ this._emitter.on(event, listener);
2553
+ }
2554
+ off(event, listener) {
2555
+ this._emitter.off(event, listener);
2556
+ }
2557
+ /**
2558
+ * Stop the underlying connection and reset client state. Idempotent.
2559
+ *
2560
+ * After resolution the client returns to its initial state and may
2561
+ * be started again via `start()`. Callers that want the same identity
2562
+ * should keep their authentication source (URL or credential)
2563
+ * constant.
2564
+ *
2565
+ * Stopping is not cancellable: it tears down the transport and clears
2566
+ * local state, mirroring the underlying `WebPubSubClient.stop()`, which
2567
+ * takes no options.
2568
+ */
2569
+ async stop() {
2570
+ const startPromise = this._startPromise;
2571
+ if (startPromise) {
2572
+ await startPromise.catch(() => void 0);
2573
+ }
2574
+ this._startPromise = void 0;
2575
+ this.resetState();
2576
+ await this.stopConnection();
2577
+ }
2578
+ /**
2579
+ * Reset chat-domain state. Emits `"stopped"` exactly once per
2580
+ * started → not-started transition: if `_isStarted` was already
2581
+ * false on entry (e.g. the pre-start guard inside `startCore()` or
2582
+ * the post-failure rollback), no event fires.
2583
+ */
2584
+ resetState() {
2585
+ const wasStarted = this._isStarted;
2586
+ this._isStarted = false;
2587
+ this._userId = void 0;
2588
+ this._rooms.clear();
2589
+ this._conversationIds.clear();
2590
+ if (wasStarted) {
2591
+ const stoppedEvent = {};
2592
+ this._emitter.emit("stopped", stoppedEvent);
2593
+ }
2594
+ }
2595
+ async stopConnection() {
2596
+ const connectionStoppedTCS = this._connectionStoppedTCS;
2597
+ if (!connectionStoppedTCS) {
2598
+ return;
2599
+ }
2600
+ if (!this._isConnectionStopping) {
2601
+ this._isConnectionStopping = true;
2602
+ try {
2603
+ this._connection.stop();
2604
+ } catch (err) {
2605
+ this._isConnectionStopping = false;
2606
+ throw err;
2607
+ }
2608
+ }
2609
+ await connectionStoppedTCS.wait();
2610
+ }
2611
+ };
2612
+
2613
+ // src/index.ts
2614
+ var KnownChatErrorCode = ERRORS;
2615
+ export {
2616
+ ChatClient,
2617
+ ChatError,
2618
+ KnownChatErrorCode
2619
+ };
2620
+ //# sourceMappingURL=index.js.map