@turingfocus/chat-gateway-tfrobot 0.6.0 → 0.7.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/dist/socket.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { io } from "socket.io-client";
2
- import { chatErrorSchema, chatUpdateSchema, createGatewayDeadlineExceededError, isGatewayDeadlineExceeded, } from "@turingfocus/chat-protocol";
2
+ import { chatErrorSchema, chatUpdateSchema, createGatewayDeadlineExceededError, getTimelineItemKey, isGatewayDeadlineExceeded, } from "@turingfocus/chat-protocol";
3
3
  import { awaitBounded } from "./bounded.js";
4
4
  import { chatErrorEventDtoSchema, eventDtoSchema, messageDtoSchema, socketProtocolErrorDtoSchema, stateChangedDtoSchema, statusDtoSchema, } from "./dto.js";
5
5
  import { mapEventUpdate, mapMessageUpdate, mapRun, mapUnknownSocketEvent, } from "./mapper.js";
6
6
  import { sanitizeCredentialError, sanitizeCredentialRaw, sanitizeCredentialText, } from "./redaction.js";
7
- import { isValidTFRobotSession } from "./types.js";
7
+ import { isValidTFRobotSession, resolveTFRobotServerProfile } from "./types.js";
8
8
  const KNOWN_EVENTS = new Set([
9
9
  "chat_error",
10
10
  "chat_event",
@@ -18,17 +18,21 @@ const KNOWN_EVENTS = new Set([
18
18
  const MAX_TIMER_DELAY = 2_147_483_647;
19
19
  const RECONNECT_AUTH_TIMEOUT_MS = 10_000;
20
20
  const RECONNECT_JOIN_TIMEOUT_MS = 10_000;
21
- const parseJoinAcknowledgement = (value, reconnect) => {
21
+ const parseJoinAcknowledgement = (value, reconnect, acceptEmpty) => {
22
22
  if (value === undefined) {
23
23
  return {
24
- accepted: reconnect,
24
+ accepted: reconnect || acceptEmpty,
25
+ empty: true,
25
26
  recoveryComplete: false,
26
- ...(reconnect ? {} : { rejectionCode: "validation" }),
27
+ ...(reconnect || acceptEmpty
28
+ ? {}
29
+ : { rejectionCode: "validation" }),
27
30
  };
28
31
  }
29
32
  if (value === null) {
30
33
  return {
31
34
  accepted: false,
35
+ empty: false,
32
36
  recoveryComplete: false,
33
37
  rejectionCode: "validation",
34
38
  };
@@ -36,16 +40,18 @@ const parseJoinAcknowledgement = (value, reconnect) => {
36
40
  if (value === false) {
37
41
  return {
38
42
  accepted: false,
43
+ empty: false,
39
44
  recoveryComplete: false,
40
45
  rejectionCode: "validation",
41
46
  };
42
47
  }
43
48
  if (value === true) {
44
- return { accepted: true, recoveryComplete: !reconnect };
49
+ return { accepted: true, empty: false, recoveryComplete: !reconnect };
45
50
  }
46
51
  if (typeof value !== "object") {
47
52
  return {
48
53
  accepted: false,
54
+ empty: false,
49
55
  recoveryComplete: false,
50
56
  rejectionCode: "validation",
51
57
  };
@@ -120,6 +126,7 @@ const parseJoinAcknowledgement = (value, reconnect) => {
120
126
  const authorizationRejected = statuses.some(({ normalized, numeric }) => numeric === 403 || normalized === "forbidden") || normalizedError === "forbidden";
121
127
  return {
122
128
  accepted,
129
+ empty: false,
123
130
  ...(authenticationRejected
124
131
  ? { rejectionCode: "authentication" }
125
132
  : authorizationRejected
@@ -218,27 +225,65 @@ export const createSocketIoFactoryWith = (connect) => ({ getAuth, namespaceUrl,
218
225
  },
219
226
  });
220
227
  export const createSocketIoFactory = createSocketIoFactoryWith(io);
228
+ const MAX_RECOVERY_IDENTITIES = 10_000;
229
+ const rememberBoundedSetValue = (values, value) => {
230
+ values.delete(value);
231
+ values.add(value);
232
+ while (values.size > MAX_RECOVERY_IDENTITIES) {
233
+ const oldest = values.values().next().value;
234
+ if (oldest === undefined)
235
+ break;
236
+ values.delete(oldest);
237
+ }
238
+ };
239
+ const rememberBoundedMapValue = (values, key, value) => {
240
+ values.delete(key);
241
+ values.set(key, value);
242
+ while (values.size > MAX_RECOVERY_IDENTITIES) {
243
+ const oldest = values.keys().next().value;
244
+ if (oldest === undefined)
245
+ break;
246
+ values.delete(oldest);
247
+ }
248
+ };
249
+ export const recoveryIdentityOfUpdate = (update) => {
250
+ if (update.kind === "timeline.upsert") {
251
+ return getTimelineItemKey(update.item);
252
+ }
253
+ if (update.kind === "event.transition.upsert") {
254
+ return `event:${update.event.id}:transition:${update.event.transition.id}`;
255
+ }
256
+ return undefined;
257
+ };
258
+ const recoveryIdentitiesOfSnapshot = (snapshot) => snapshot.timeline.flatMap((item) => item.kind === "agent-event"
259
+ ? item.transitions.map((transition) => `event:${item.id}:transition:${transition.id}`)
260
+ : [getTimelineItemKey(item)]);
221
261
  export class TFRobotSocketClient {
222
262
  #disposed = false;
223
- #establishmentAbort;
224
263
  #establishing;
264
+ #pendingEstablishment;
225
265
  #factory;
226
266
  #namespaceUrl;
227
267
  #now;
228
268
  #options;
229
269
  #path;
270
+ #profile;
271
+ #currentServerRestLoader;
230
272
  #reconnectStatusLoader;
273
+ #recoveryCheckpoints = new Map();
231
274
  #runs = new Map();
232
275
  #subscriptions = new Set();
233
276
  #subscriptionGeneration = 0;
234
- constructor(options, reconnectStatusLoader) {
277
+ constructor(options, reconnectStatusLoader, currentServerRestLoader) {
235
278
  this.#options = options;
236
279
  this.#factory = options.socketFactory ?? createSocketIoFactory;
237
280
  this.#path = options.socketPath ?? "/socket.io";
238
281
  this.#now = options.now ?? Date.now;
282
+ this.#profile = resolveTFRobotServerProfile(options.serverProfile);
239
283
  this.#namespaceUrl =
240
284
  options.socketNamespaceUrl ?? this.#defaultNamespaceUrl(options.baseUrl);
241
285
  this.#reconnectStatusLoader = reconnectStatusLoader;
286
+ this.#currentServerRestLoader = currentServerRestLoader;
242
287
  }
243
288
  async subscribe(conversationId, options, observer) {
244
289
  if (this.#disposed) {
@@ -257,14 +302,25 @@ export class TFRobotSocketClient {
257
302
  const subscriptionId = `tfrobot-subscription-${generation}`;
258
303
  this.#cancelEstablishment();
259
304
  const establishmentAbort = new AbortController();
260
- this.#establishmentAbort = establishmentAbort;
261
- const authOutcome = await awaitBounded(() => this.#getSocketAuth(conversationId, "connect"), {
305
+ const pendingEstablishment = {
306
+ abort: establishmentAbort,
307
+ conversationId,
308
+ generation,
309
+ };
310
+ this.#pendingEstablishment = pendingEstablishment;
311
+ const clearPendingEstablishment = () => {
312
+ if (this.#pendingEstablishment === pendingEstablishment) {
313
+ this.#pendingEstablishment = undefined;
314
+ }
315
+ };
316
+ const authOutcome = await awaitBounded(() => this.#getSocketSession(conversationId, "connect"), {
262
317
  deadlineAt: options.deadlineAt,
263
318
  now: this.#now,
264
319
  signal: establishmentAbort.signal,
265
320
  });
266
321
  switch (authOutcome.kind) {
267
322
  case "aborted": {
323
+ clearPendingEstablishment();
268
324
  return {
269
325
  ok: false,
270
326
  error: this.#error("conflict", this.#disposed
@@ -273,12 +329,14 @@ export class TFRobotSocketClient {
273
329
  };
274
330
  }
275
331
  case "deadline": {
332
+ clearPendingEstablishment();
276
333
  return {
277
334
  ok: false,
278
335
  error: createGatewayDeadlineExceededError(),
279
336
  };
280
337
  }
281
338
  case "error": {
339
+ clearPendingEstablishment();
282
340
  return {
283
341
  ok: false,
284
342
  error: this.#error("authentication", "Unable to obtain a TFRobot Socket session", true, undefined),
@@ -289,14 +347,43 @@ export class TFRobotSocketClient {
289
347
  }
290
348
  }
291
349
  if (this.#disposed || establishmentAbort.signal.aborted) {
350
+ clearPendingEstablishment();
292
351
  return {
293
352
  ok: false,
294
353
  error: this.#error("conflict", "TFRobot Gateway was disposed during subscription", false, undefined),
295
354
  };
296
355
  }
297
- const credentialValues = new Set(Object.values(authOutcome.value));
356
+ const initialSession = authOutcome.value;
357
+ if (this.#profile.kind === "current-server") {
358
+ const preflight = await this.#currentServerRestLoader({
359
+ checkpoint: new Set(),
360
+ conversationId,
361
+ deadlineAt: options.deadlineAt,
362
+ limits: {
363
+ ...this.#profile.rebase,
364
+ maxItems: this.#profile.rebase.pageSize,
365
+ maxPages: 1,
366
+ },
367
+ session: initialSession,
368
+ signal: establishmentAbort.signal,
369
+ });
370
+ if (this.#disposed || establishmentAbort.signal.aborted) {
371
+ clearPendingEstablishment();
372
+ return {
373
+ ok: false,
374
+ error: this.#error("conflict", "TFRobot subscription was replaced during REST preflight", false, undefined),
375
+ };
376
+ }
377
+ if (!preflight.ok) {
378
+ clearPendingEstablishment();
379
+ return preflight;
380
+ }
381
+ }
382
+ const initialAuth = authOf(initialSession);
383
+ const credentialValues = new Set(Object.values(initialAuth));
298
384
  const errorConversationId = () => sanitizeCredentialText(conversationId, credentialValues);
299
- let firstAuth = authOutcome.value;
385
+ let firstAuth = initialAuth;
386
+ let currentServerSession = initialSession;
300
387
  let authenticationFailure;
301
388
  const connectionAbort = new AbortController();
302
389
  let socket;
@@ -313,20 +400,22 @@ export class TFRobotSocketClient {
313
400
  firstAuth = undefined;
314
401
  return auth;
315
402
  }
316
- const reconnectAuth = await awaitBounded(() => this.#getSocketAuth(conversationId, "reconnect"), {
403
+ const reconnectSession = await awaitBounded(() => this.#getSocketSession(conversationId, "reconnect"), {
317
404
  deadlineAt: this.#now() + RECONNECT_AUTH_TIMEOUT_MS,
318
405
  now: this.#now,
319
406
  signal: connectionAbort.signal,
320
407
  });
321
- if (reconnectAuth.kind === "value") {
322
- for (const value of Object.values(reconnectAuth.value)) {
408
+ if (reconnectSession.kind === "value") {
409
+ currentServerSession = reconnectSession.value;
410
+ const reconnectAuth = authOf(reconnectSession.value);
411
+ for (const value of Object.values(reconnectAuth)) {
323
412
  credentialValues.add(value);
324
413
  }
325
- return reconnectAuth.value;
414
+ return reconnectAuth;
326
415
  }
327
- const reason = reconnectAuth.kind === "error"
328
- ? reconnectAuth.reason
329
- : new Error(reconnectAuth.kind === "deadline"
416
+ const reason = reconnectSession.kind === "error"
417
+ ? reconnectSession.reason
418
+ : new Error(reconnectSession.kind === "deadline"
330
419
  ? "TFRobot Socket session refresh exceeded its deadline"
331
420
  : "TFRobot Socket session refresh was cancelled");
332
421
  authenticationFailure = reason;
@@ -336,6 +425,7 @@ export class TFRobotSocketClient {
336
425
  }
337
426
  catch (reason) {
338
427
  connectionAbort.abort();
428
+ clearPendingEstablishment();
339
429
  return {
340
430
  ok: false,
341
431
  error: this.#transportError(reason, "Unable to create the TFRobot Socket transport", conversationId, credentialValues),
@@ -496,12 +586,18 @@ export class TFRobotSocketClient {
496
586
  ? {}
497
587
  : {
498
588
  recoveryComplete: recovery.complete,
589
+ ...(recovery.assurance === undefined
590
+ ? {}
591
+ : { recoveryAssurance: recovery.assurance }),
499
592
  ...(recovery.cursor === undefined
500
593
  ? {}
501
594
  : { recoveryCursor: recovery.cursor }),
502
595
  ...(recovery.reason === undefined
503
596
  ? {}
504
597
  : { recoveryReason: recovery.reason }),
598
+ ...(recovery.source === undefined
599
+ ? {}
600
+ : { recoverySource: recovery.source }),
505
601
  }),
506
602
  })).catch(() => undefined);
507
603
  }
@@ -533,8 +629,74 @@ export class TFRobotSocketClient {
533
629
  report(this.#error("validation", invalidMessage, false, errorConversationId()));
534
630
  return;
535
631
  }
632
+ const recoveryIdentity = recoveryIdentityOfUpdate(update);
633
+ if (recoveryIdentity !== undefined) {
634
+ active.realtimeRevision += 1;
635
+ rememberBoundedMapValue(active.realtimeIdentityRevisions, recoveryIdentity, active.realtimeRevision);
636
+ const checkpoint = this.#recoveryCheckpoints.get(conversationId) ?? new Set();
637
+ rememberBoundedSetValue(checkpoint, recoveryIdentity);
638
+ this.#recoveryCheckpoints.set(conversationId, checkpoint);
639
+ }
536
640
  next(update);
537
641
  };
642
+ const rebaseCurrentServer = async (recoveryRevision, runRevision, session, checkpoint, realtimeRevision) => {
643
+ if (this.#profile.kind !== "current-server") {
644
+ return { kind: "failure" };
645
+ }
646
+ const result = await this.#currentServerRestLoader({
647
+ checkpoint,
648
+ conversationId,
649
+ deadlineAt: this.#now() + this.#profile.rebase.deadlineMs,
650
+ limits: this.#profile.rebase,
651
+ session,
652
+ signal: connectionAbort.signal,
653
+ });
654
+ if (!active.active ||
655
+ !this.#subscriptions.has(active) ||
656
+ !active.socket.connected ||
657
+ active.recoveryRevision !== recoveryRevision) {
658
+ return { kind: "failure" };
659
+ }
660
+ if (!result.ok) {
661
+ const error = sanitizeCredentialError(result.error, credentialValues);
662
+ if (error.code === "authentication" || error.code === "authorization") {
663
+ report(error, "authentication");
664
+ return { kind: "auth-required" };
665
+ }
666
+ report(error, "recovery");
667
+ return { kind: "failure" };
668
+ }
669
+ const remembered = this.#recoveryCheckpoints.get(conversationId) ?? new Set();
670
+ for (const update of result.value.updates) {
671
+ const identity = recoveryIdentityOfUpdate(update);
672
+ if (identity !== undefined &&
673
+ (active.realtimeIdentityRevisions.get(identity) ?? 0) >
674
+ realtimeRevision) {
675
+ continue;
676
+ }
677
+ next(update);
678
+ if (identity !== undefined)
679
+ rememberBoundedSetValue(remembered, identity);
680
+ }
681
+ this.#recoveryCheckpoints.set(conversationId, remembered);
682
+ if (active.runRevision === runRevision) {
683
+ const previous = this.#runs.get(conversationId);
684
+ this.#runs.set(conversationId, result.value.run);
685
+ if (!sameRun(previous, result.value.run)) {
686
+ next(chatUpdateSchema.parse({
687
+ kind: "run.replace",
688
+ conversationId: errorConversationId(),
689
+ run: result.value.run,
690
+ }));
691
+ }
692
+ }
693
+ const reason = result.value.checkpointReached
694
+ ? "rest-rebase-reached-checkpoint"
695
+ : result.value.boundedBy === undefined
696
+ ? "rest-rebase-history-exhausted"
697
+ : `rest-rebase-${result.value.boundedBy}`;
698
+ return { kind: "success", reason };
699
+ };
538
700
  let settleEstablishment;
539
701
  add("connect", () => {
540
702
  if (!active.active)
@@ -563,6 +725,8 @@ export class TFRobotSocketClient {
563
725
  const reconnect = subscriptionEstablished;
564
726
  if (reconnect)
565
727
  active.reconnectAttempt += 1;
728
+ const rebaseCheckpoint = new Set(this.#recoveryCheckpoints.get(conversationId) ?? []);
729
+ const rebaseRealtimeRevision = active.realtimeRevision;
566
730
  const recoveryRevision = ++active.recoveryRevision;
567
731
  const runRevision = active.runRevision;
568
732
  const joinStartedAt = this.#now();
@@ -589,11 +753,12 @@ export class TFRobotSocketClient {
589
753
  const rawAcknowledgement = acknowledgementArguments[0];
590
754
  acknowledgement = parseJoinAcknowledgement(rawAcknowledgement === undefined || rawAcknowledgement === true
591
755
  ? rawAcknowledgement
592
- : sanitizeCredentialRaw(rawAcknowledgement, credentialValues), reconnect);
756
+ : sanitizeCredentialRaw(rawAcknowledgement, credentialValues), reconnect, this.#profile.kind === "current-server");
593
757
  }
594
758
  catch {
595
759
  acknowledgement = {
596
760
  accepted: false,
761
+ empty: false,
597
762
  recoveryComplete: false,
598
763
  rejectionCode: "validation",
599
764
  message: "Invalid TFRobot conversation subscription acknowledgement",
@@ -661,12 +826,24 @@ export class TFRobotSocketClient {
661
826
  });
662
827
  resolveError("connection");
663
828
  resolveError("authentication");
664
- lifecycle("active", {
665
- complete: true,
666
- ...(acknowledgement.cursor === undefined
667
- ? {}
668
- : { cursor: acknowledgement.cursor }),
669
- }, this.#now() - joinStartedAt);
829
+ if (this.#profile.kind === "current-server" &&
830
+ acknowledgement.empty) {
831
+ lifecycle("degraded", {
832
+ assurance: "best-effort",
833
+ complete: false,
834
+ reason: "initial-rest-preflight",
835
+ source: "rest-rebase",
836
+ }, this.#now() - joinStartedAt);
837
+ }
838
+ else {
839
+ lifecycle("active", {
840
+ complete: true,
841
+ ...(acknowledgement.cursor === undefined
842
+ ? {}
843
+ : { cursor: acknowledgement.cursor }),
844
+ }, this.#now() - joinStartedAt);
845
+ }
846
+ currentServerSession = undefined;
670
847
  active.acceptingEvents = true;
671
848
  flushRealtime();
672
849
  return;
@@ -684,6 +861,48 @@ export class TFRobotSocketClient {
684
861
  }, joinLatencyMs);
685
862
  active.acceptingEvents = true;
686
863
  flushRealtime();
864
+ if (this.#profile.kind === "current-server" &&
865
+ !acknowledgement.recoveryComplete) {
866
+ const recoverySession = currentServerSession;
867
+ currentServerSession = undefined;
868
+ if (recoverySession === undefined) {
869
+ report(this.#error("authentication", "TFRobot reconnect did not provide a session for REST rebase", true, errorConversationId()), "recovery");
870
+ return;
871
+ }
872
+ void rebaseCurrentServer(recoveryRevision, runRevision, recoverySession, rebaseCheckpoint, rebaseRealtimeRevision)
873
+ .then((outcome) => {
874
+ if (!active.active ||
875
+ !this.#subscriptions.has(active) ||
876
+ !active.socket.connected ||
877
+ active.recoveryRevision !== recoveryRevision) {
878
+ return;
879
+ }
880
+ if (outcome.kind === "auth-required") {
881
+ enterAuthRequired();
882
+ return;
883
+ }
884
+ if (outcome.kind !== "success")
885
+ return;
886
+ resolveError("connection");
887
+ resolveError("recovery");
888
+ resolveError("authentication");
889
+ active.manualReconnectAttempted = false;
890
+ active.manualReconnectPending = false;
891
+ active.authRequired = false;
892
+ active.terminal = false;
893
+ lifecycle("degraded", {
894
+ assurance: "best-effort",
895
+ complete: false,
896
+ reason: outcome.reason,
897
+ source: "rest-rebase",
898
+ }, joinLatencyMs);
899
+ })
900
+ .catch(() => {
901
+ report(this.#error("unknown", "TFRobot REST rebase failed unexpectedly", true, errorConversationId()), "recovery");
902
+ });
903
+ return;
904
+ }
905
+ currentServerSession = undefined;
687
906
  void this.#reconcileRunAfterReconnect(active, conversationId, credentialValues, recoveryRevision, runRevision, next, report)
688
907
  .then((outcome) => {
689
908
  if (outcome === "auth-required") {
@@ -987,6 +1206,7 @@ export class TFRobotSocketClient {
987
1206
  // Adapter ownership is cleared even if an injected transport misbehaves.
988
1207
  }
989
1208
  firstAuth = undefined;
1209
+ currentServerSession = undefined;
990
1210
  credentialValues.clear();
991
1211
  pendingNotifications.length = 0;
992
1212
  pendingRealtimeActions.length = 0;
@@ -994,6 +1214,7 @@ export class TFRobotSocketClient {
994
1214
  if (setupFailure !== undefined) {
995
1215
  const error = this.#transportError(setupFailure.reason, "Unable to configure the TFRobot Socket transport", conversationId, credentialValues);
996
1216
  cleanup();
1217
+ clearPendingEstablishment();
997
1218
  return {
998
1219
  ok: false,
999
1220
  error,
@@ -1016,6 +1237,8 @@ export class TFRobotSocketClient {
1016
1237
  manualReconnectPending: false,
1017
1238
  observer,
1018
1239
  reconnectAttempt: 0,
1240
+ realtimeIdentityRevisions: new Map(),
1241
+ realtimeRevision: 0,
1019
1242
  recoveryRevision: 0,
1020
1243
  runRevision: 0,
1021
1244
  socket,
@@ -1031,9 +1254,7 @@ export class TFRobotSocketClient {
1031
1254
  return;
1032
1255
  settled = true;
1033
1256
  settleEstablishment = undefined;
1034
- if (this.#establishmentAbort === establishmentAbort) {
1035
- this.#establishmentAbort = undefined;
1036
- }
1257
+ clearPendingEstablishment();
1037
1258
  if (this.#establishing === active)
1038
1259
  this.#establishing = undefined;
1039
1260
  clearTimeout(timeout);
@@ -1087,16 +1308,46 @@ export class TFRobotSocketClient {
1087
1308
  subscription.cleanup();
1088
1309
  }
1089
1310
  this.#subscriptions.clear();
1311
+ this.#recoveryCheckpoints.clear();
1090
1312
  this.#runs.clear();
1091
1313
  }
1314
+ rememberSnapshot(snapshot) {
1315
+ if (this.#disposed)
1316
+ return;
1317
+ const conversationId = snapshot.conversation.id;
1318
+ this.#runs.set(conversationId, snapshot.run);
1319
+ const checkpoint = this.#recoveryCheckpoints.get(conversationId) ?? new Set();
1320
+ for (const identity of recoveryIdentitiesOfSnapshot(snapshot)) {
1321
+ rememberBoundedSetValue(checkpoint, identity);
1322
+ }
1323
+ this.#recoveryCheckpoints.set(conversationId, checkpoint);
1324
+ }
1092
1325
  rememberRun(conversationId, run) {
1093
1326
  if (this.#disposed)
1094
1327
  return;
1095
1328
  this.#runs.set(conversationId, run);
1096
1329
  }
1330
+ forgetConversation(conversationId) {
1331
+ if (this.#disposed)
1332
+ return;
1333
+ if (this.#pendingEstablishment?.conversationId === conversationId ||
1334
+ this.#establishing?.conversationId === conversationId) {
1335
+ this.#cancelEstablishment();
1336
+ }
1337
+ for (const subscription of [...this.#subscriptions]) {
1338
+ if (subscription.conversationId !== conversationId)
1339
+ continue;
1340
+ subscription.active = false;
1341
+ subscription.recoveryRevision += 1;
1342
+ subscription.cleanup();
1343
+ this.#subscriptions.delete(subscription);
1344
+ }
1345
+ this.#recoveryCheckpoints.delete(conversationId);
1346
+ this.#runs.delete(conversationId);
1347
+ }
1097
1348
  #cancelEstablishment() {
1098
- this.#establishmentAbort?.abort();
1099
- this.#establishmentAbort = undefined;
1349
+ this.#pendingEstablishment?.abort.abort();
1350
+ this.#pendingEstablishment = undefined;
1100
1351
  this.#establishing?.cancelEstablishment();
1101
1352
  this.#establishing = undefined;
1102
1353
  }
@@ -1107,7 +1358,7 @@ export class TFRobotSocketClient {
1107
1358
  url.hash = "";
1108
1359
  return url.toString().replace(/\/$/u, "");
1109
1360
  }
1110
- async #getSocketAuth(conversationId, purpose) {
1361
+ async #getSocketSession(conversationId, purpose) {
1111
1362
  const session = await this.#options.sessionProvider.getSession({
1112
1363
  purpose,
1113
1364
  operation: "subscribe",
@@ -1116,7 +1367,7 @@ export class TFRobotSocketClient {
1116
1367
  if (!isValidTFRobotSession(session)) {
1117
1368
  throw new TypeError("SessionProvider returned invalid TFRobot credentials");
1118
1369
  }
1119
- return authOf(session);
1370
+ return session;
1120
1371
  }
1121
1372
  async #reconcileRunAfterReconnect(active, conversationId, credentialValues, recoveryRevision, runRevision, next, report) {
1122
1373
  const result = await this.#reconnectStatusLoader(conversationId);