@q9labsai/chalk-client 4.1.17 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +60 -42
  2. package/dist/access/grant.d.ts +0 -10
  3. package/dist/access/grant.d.ts.map +1 -1
  4. package/dist/access/manager.d.ts.map +1 -1
  5. package/dist/{chunk-ZRMGKMX4.js → chunk-2HJIJVE2.js} +552 -3651
  6. package/dist/{chunk-CZUJNAUI.js → chunk-AVXJ4HQU.js} +142 -49
  7. package/dist/{chunk-A7BVZEFM.js → chunk-CMVO7USN.js} +2 -8
  8. package/dist/{chunk-AUQTQOLR.js → chunk-IPAN4LUZ.js} +627 -2434
  9. package/dist/{chunk-2DZUHV6I.js → chunk-O2NOZKJP.js} +129 -721
  10. package/dist/client.d.ts +2559 -5303
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/collaboration/types.d.ts +21 -1
  13. package/dist/collaboration/types.d.ts.map +1 -1
  14. package/dist/collaboration/wire.d.ts +8 -1
  15. package/dist/collaboration/wire.d.ts.map +1 -1
  16. package/dist/connection/dependencies.d.ts +7 -13
  17. package/dist/connection/dependencies.d.ts.map +1 -1
  18. package/dist/connection/index.d.ts +1 -6
  19. package/dist/connection/index.d.ts.map +1 -1
  20. package/dist/connection/lifecycle.d.ts.map +1 -1
  21. package/dist/connection/media-devices.d.ts +11 -0
  22. package/dist/connection/media-devices.d.ts.map +1 -1
  23. package/dist/connection/production.d.ts +1 -1
  24. package/dist/connection/production.d.ts.map +1 -1
  25. package/dist/connection/types.d.ts +4 -4
  26. package/dist/connection/types.d.ts.map +1 -1
  27. package/dist/effect.d.ts +0 -4
  28. package/dist/effect.d.ts.map +1 -1
  29. package/dist/effect.js +53 -776
  30. package/dist/generated/http-api.d.ts +2603 -5293
  31. package/dist/generated/http-api.d.ts.map +1 -1
  32. package/dist/generated/schemas.d.ts +1893 -6870
  33. package/dist/generated/schemas.d.ts.map +1 -1
  34. package/dist/generated/sync.d.ts +191 -28
  35. package/dist/generated/sync.d.ts.map +1 -1
  36. package/dist/generated/whiteboard-v1.d.ts +0 -7
  37. package/dist/generated/whiteboard-v1.d.ts.map +1 -1
  38. package/dist/index.d.ts +0 -4
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +10 -119
  41. package/dist/media/client.d.ts +6 -5
  42. package/dist/media/client.d.ts.map +1 -1
  43. package/dist/media/index.d.ts +1 -2
  44. package/dist/media/index.d.ts.map +1 -1
  45. package/dist/media/index.js +1 -7
  46. package/dist/media/plane.d.ts +12 -1
  47. package/dist/media/plane.d.ts.map +1 -1
  48. package/dist/media/target.d.ts +4 -2
  49. package/dist/media/target.d.ts.map +1 -1
  50. package/dist/media/tracks.d.ts +2 -2
  51. package/dist/media/tracks.d.ts.map +1 -1
  52. package/dist/media/transport.d.ts.map +1 -1
  53. package/dist/media/types.d.ts +4 -11
  54. package/dist/media/types.d.ts.map +1 -1
  55. package/dist/public-invites/client.d.ts.map +1 -1
  56. package/dist/public-invites/index.d.ts +2 -2
  57. package/dist/public-invites/index.d.ts.map +1 -1
  58. package/dist/public-invites/index.js +2 -5
  59. package/dist/public-invites/types.d.ts +2 -6
  60. package/dist/public-invites/types.d.ts.map +1 -1
  61. package/dist/server/client.d.ts.map +1 -1
  62. package/dist/server/index.cjs +12 -112
  63. package/dist/server/index.d.cts +1 -1
  64. package/dist/server/index.d.ts +1 -1
  65. package/dist/server/index.d.ts.map +1 -1
  66. package/dist/server/index.js +9 -109
  67. package/dist/server/types.d.cts +0 -7
  68. package/dist/server/types.d.ts +0 -7
  69. package/dist/server/types.d.ts.map +1 -1
  70. package/dist/space-client/chat-controller-helpers.d.ts.map +1 -1
  71. package/dist/space-client/chat-controller.d.ts +2 -3
  72. package/dist/space-client/chat-controller.d.ts.map +1 -1
  73. package/dist/space-client/controller-effects.d.ts +0 -3
  74. package/dist/space-client/controller-effects.d.ts.map +1 -1
  75. package/dist/space-client/core.d.ts +3 -18
  76. package/dist/space-client/core.d.ts.map +1 -1
  77. package/dist/space-client/core.test.helpers.d.ts.map +1 -1
  78. package/dist/space-client/effect.d.ts +0 -2
  79. package/dist/space-client/effect.d.ts.map +1 -1
  80. package/dist/space-client/index.d.ts +1 -2
  81. package/dist/space-client/index.d.ts.map +1 -1
  82. package/dist/space-client/media-controller.d.ts +4 -4
  83. package/dist/space-client/media-controller.d.ts.map +1 -1
  84. package/dist/space-client/offline-actions-storage.d.ts +18 -3
  85. package/dist/space-client/offline-actions-storage.d.ts.map +1 -1
  86. package/dist/space-client/offline-actions.d.ts +1 -0
  87. package/dist/space-client/offline-actions.d.ts.map +1 -1
  88. package/dist/space-client/participants-controller.d.ts +2 -3
  89. package/dist/space-client/participants-controller.d.ts.map +1 -1
  90. package/dist/space-client/reactions-controller.d.ts +2 -3
  91. package/dist/space-client/reactions-controller.d.ts.map +1 -1
  92. package/dist/space-client/recording-controller.d.ts +2 -3
  93. package/dist/space-client/recording-controller.d.ts.map +1 -1
  94. package/dist/space-client/space-client.d.ts.map +1 -1
  95. package/dist/space-client/store.d.ts.map +1 -1
  96. package/dist/space-client/terminal.test.helpers.d.ts +33 -12
  97. package/dist/space-client/terminal.test.helpers.d.ts.map +1 -1
  98. package/dist/space-client/types.d.ts +15 -8
  99. package/dist/space-client/types.d.ts.map +1 -1
  100. package/dist/sync/index.d.ts +1 -1
  101. package/dist/sync/index.d.ts.map +1 -1
  102. package/dist/sync/index.js +1 -3
  103. package/dist/sync/v1-client.d.ts +4 -3
  104. package/dist/sync/v1-client.d.ts.map +1 -1
  105. package/dist/sync/v1-collaboration-state.d.ts +10 -3
  106. package/dist/sync/v1-collaboration-state.d.ts.map +1 -1
  107. package/dist/sync/v1-types.d.ts +10 -9
  108. package/dist/sync/v1-types.d.ts.map +1 -1
  109. package/dist/whiteboard/file-download-transport.d.ts +8 -0
  110. package/dist/whiteboard/file-download-transport.d.ts.map +1 -0
  111. package/dist/whiteboard/index.d.ts +1 -1
  112. package/dist/whiteboard/index.d.ts.map +1 -1
  113. package/dist/whiteboard/types.d.ts +12 -15
  114. package/dist/whiteboard/types.d.ts.map +1 -1
  115. package/dist/whiteboard/v1-client.d.ts.map +1 -1
  116. package/package.json +4 -16
  117. package/dist/access/episode-diagnostic-credential.d.ts +0 -11
  118. package/dist/access/episode-diagnostic-credential.d.ts.map +0 -1
  119. package/dist/chunk-EWTITNJ3.js +0 -1163
  120. package/dist/chunk-HW5TTZL2.js +0 -99
  121. package/dist/chunk-PBSYXPNJ.js +0 -23
  122. package/dist/chunk-RCDXIDCN.js +0 -33
  123. package/dist/connection/snapshot.d.ts +0 -23
  124. package/dist/connection/snapshot.d.ts.map +0 -1
  125. package/dist/feedback/collector.d.ts +0 -14
  126. package/dist/feedback/collector.d.ts.map +0 -1
  127. package/dist/feedback/context.d.ts +0 -38
  128. package/dist/feedback/context.d.ts.map +0 -1
  129. package/dist/feedback/controller.d.ts +0 -4
  130. package/dist/feedback/controller.d.ts.map +0 -1
  131. package/dist/feedback/index.d.ts +0 -7
  132. package/dist/feedback/index.d.ts.map +0 -1
  133. package/dist/feedback/transport.d.ts +0 -29
  134. package/dist/feedback/transport.d.ts.map +0 -1
  135. package/dist/feedback/types.d.ts +0 -202
  136. package/dist/feedback/types.d.ts.map +0 -1
  137. package/dist/feedback/validation.d.ts +0 -30
  138. package/dist/feedback/validation.d.ts.map +0 -1
  139. package/dist/media/rtk.d.ts +0 -101
  140. package/dist/media/rtk.d.ts.map +0 -1
  141. package/dist/space-client/episode-diagnostic-registry.d.ts +0 -13
  142. package/dist/space-client/episode-diagnostic-registry.d.ts.map +0 -1
  143. package/dist/space-client/episode-diagnostic-render-registry.d.ts +0 -4
  144. package/dist/space-client/episode-diagnostic-render-registry.d.ts.map +0 -1
  145. package/dist/space-client/episode-diagnostic-runtime.d.ts +0 -105
  146. package/dist/space-client/episode-diagnostic-runtime.d.ts.map +0 -1
  147. package/dist/telemetry/attributes.d.ts +0 -7
  148. package/dist/telemetry/attributes.d.ts.map +0 -1
  149. package/dist/telemetry/client.d.ts +0 -44
  150. package/dist/telemetry/client.d.ts.map +0 -1
  151. package/dist/telemetry/delivery.d.ts +0 -107
  152. package/dist/telemetry/delivery.d.ts.map +0 -1
  153. package/dist/telemetry/exporter.d.ts +0 -38
  154. package/dist/telemetry/exporter.d.ts.map +0 -1
  155. package/dist/telemetry/index.d.ts +0 -7
  156. package/dist/telemetry/index.d.ts.map +0 -1
  157. package/dist/telemetry/index.js +0 -50
  158. package/dist/telemetry/journey.d.ts +0 -52
  159. package/dist/telemetry/journey.d.ts.map +0 -1
  160. package/dist/telemetry/random.d.ts +0 -18
  161. package/dist/telemetry/random.d.ts.map +0 -1
  162. package/dist/telemetry/reconnect.d.ts +0 -7
  163. package/dist/telemetry/reconnect.d.ts.map +0 -1
  164. package/dist/telemetry/rtc.d.ts +0 -41
  165. package/dist/telemetry/rtc.d.ts.map +0 -1
  166. package/dist/telemetry/storage.d.ts +0 -22
  167. package/dist/telemetry/storage.d.ts.map +0 -1
  168. package/dist/telemetry/sync.d.ts +0 -10
  169. package/dist/telemetry/sync.d.ts.map +0 -1
  170. package/dist/telemetry/test-support.d.ts +0 -51
  171. package/dist/telemetry/test-support.d.ts.map +0 -1
  172. package/dist/telemetry/trace.d.ts +0 -18
  173. package/dist/telemetry/trace.d.ts.map +0 -1
  174. package/dist/telemetry/types.d.ts +0 -109
  175. package/dist/telemetry/types.d.ts.map +0 -1
  176. package/dist/whiteboard/file-http-transport.d.ts +0 -9
  177. package/dist/whiteboard/file-http-transport.d.ts.map +0 -1
@@ -1,11 +1,3 @@
1
- import {
2
- recordReconnect,
3
- traceReconnect
4
- } from "./chunk-RCDXIDCN.js";
5
- import {
6
- journeyHeaders
7
- } from "./chunk-HW5TTZL2.js";
8
-
9
1
  // src/media/camera-uplink.ts
10
2
  var CameraUplinkPolicy = class {
11
3
  #healthySamples = 0;
@@ -46,14 +38,6 @@ function subscribeSnapshot(listeners, listener) {
46
38
  listeners.delete(listener);
47
39
  };
48
40
  }
49
- function observePublications(listeners, listener, project) {
50
- const publication = () => listener(project());
51
- listeners.add(publication);
52
- listener(project());
53
- return () => {
54
- listeners.delete(publication);
55
- };
56
- }
57
41
 
58
42
  // src/media/target.ts
59
43
  function resolveMediaTarget(participantId, stopped, tracks, target) {
@@ -203,8 +187,6 @@ var CloudflareSFUClient = class {
203
187
  #localListeners = /* @__PURE__ */ new Set();
204
188
  #onError;
205
189
  #onRemoteTrack;
206
- #recordReconnect;
207
- #onRtcSummary;
208
190
  #onScreenEnded;
209
191
  #participantId;
210
192
  #peerConnectionFactory;
@@ -225,9 +207,13 @@ var CloudflareSFUClient = class {
225
207
  #cursor = null;
226
208
  #remotePullIncomplete = false;
227
209
  #remotePullRetryAfter = /* @__PURE__ */ new Map();
210
+ #remoteParticipantIds = null;
211
+ #remoteParticipantRevision = 0;
212
+ #subscribedPublicationIds = /* @__PURE__ */ new Set();
228
213
  #generation = 0;
229
214
  #negotiatedGeneration = null;
230
215
  #replacementAttemptedGeneration = null;
216
+ #remoteRecoveryGeneration = null;
231
217
  #polling = false;
232
218
  #pollAfterCurrent = false;
233
219
  #pollFailures = 0;
@@ -247,8 +233,6 @@ var CloudflareSFUClient = class {
247
233
  this.#replaceMediaConnection = options.replaceMediaConnection;
248
234
  this.#onError = options.onError;
249
235
  this.#onRemoteTrack = options.onRemoteTrack;
250
- this.#onRtcSummary = options.onRtcSummary;
251
- this.#recordReconnect = options.recordReconnect;
252
236
  this.#onScreenEnded = options.onScreenEnded;
253
237
  this.#peerConnectionFactory = options.peerConnectionFactory;
254
238
  this.#connection = this.#createPeerConnection(options.bootstrap);
@@ -271,8 +255,13 @@ var CloudflareSFUClient = class {
271
255
  this.#remotePullRetryAfter.delete(publicationId);
272
256
  this.remotePublicationsChanged();
273
257
  }
258
+ remoteParticipantsChanged(participantIds) {
259
+ this.#remoteParticipantIds = new Set(participantIds);
260
+ this.#remoteParticipantRevision++;
261
+ this.#remotePullIncomplete = true;
262
+ this.remotePublicationsChanged();
263
+ }
274
264
  remotePublicationsChanged() {
275
- recordReconnect(this.#recordReconnect, "remote_publications_changed");
276
265
  if (this.#polling) {
277
266
  this.#pollAfterCurrent = true;
278
267
  return;
@@ -310,6 +299,17 @@ var CloudflareSFUClient = class {
310
299
  async clearPreparedLocalTrack(source) {
311
300
  const state = this.#localTracks.get(source);
312
301
  if (!state) return;
302
+ if (source === "screen_audio") {
303
+ try {
304
+ await this.#retireLocalPublication(source);
305
+ } finally {
306
+ this.#removeOwnedLocalTrack(state);
307
+ this.#localTracks.delete(source);
308
+ this.#publishSnapshot();
309
+ this.#emitLocal();
310
+ }
311
+ return;
312
+ }
313
313
  if (state.enabled) await this.#setPreparedTrackEnabled(state, false);
314
314
  if (state.transceiver) this.#reusableLocalTransceivers.set(source, state.transceiver);
315
315
  if (state.providerPublicationId) this.#reusableLocalPublicationIds.set(source, state.providerPublicationId);
@@ -326,7 +326,7 @@ var CloudflareSFUClient = class {
326
326
  const generation = this.#generation;
327
327
  this.#setPhase("connecting", null);
328
328
  await this.#activatePreparedTracks(
329
- [...this.#localTracks.values()].filter((state) => state.source !== "screen"),
329
+ [...this.#localTracks.values()].filter((state) => state.source === "microphone" || state.source === "camera"),
330
330
  generation
331
331
  );
332
332
  }
@@ -337,7 +337,7 @@ var CloudflareSFUClient = class {
337
337
  this.#pollFailedPull = false;
338
338
  try {
339
339
  const transport = this.#requireTransport();
340
- const authoritative = await traceReconnect(this.#recordReconnect, "list_publications", () => transport.listPublications());
340
+ const authoritative = await (() => transport.listPublications())();
341
341
  this.#requireGeneration(generation);
342
342
  await this.#reconcileRemotePublications(authoritative, generation);
343
343
  this.#requireGeneration(generation);
@@ -358,6 +358,11 @@ var CloudflareSFUClient = class {
358
358
  this.#schedulePoll(0);
359
359
  }
360
360
  async setLocalPublicationTarget(target) {
361
+ const result = await this.#setSinglePublicationTarget(target);
362
+ if (target.source !== "screen" || !this.#localTracks.has("screen_audio") || result.outcome !== "confirmed" && result.outcome !== "satisfied") return result;
363
+ return this.#setSinglePublicationTarget({ ...target, source: "screen_audio" });
364
+ }
365
+ async #setSinglePublicationTarget(target) {
361
366
  const resolved = resolveMediaTarget(this.#participantId, this.#stopped, this.#localTracks, target);
362
367
  if (resolved.kind === "result") return resolved.result;
363
368
  const state = resolved.value;
@@ -377,6 +382,7 @@ var CloudflareSFUClient = class {
377
382
  return target.enabled && this.#locallyPausedSources.has(target.source);
378
383
  }
379
384
  setLocalSourceIntent(source, enabled) {
385
+ if (source === "screen") this.setLocalSourceIntent("screen_audio", enabled);
380
386
  if (enabled) {
381
387
  this.#locallyPausedSources.delete(source);
382
388
  return;
@@ -390,6 +396,7 @@ var CloudflareSFUClient = class {
390
396
  async closeForcedLocalPublication(source) {
391
397
  this.setLocalSourceIntent(source, false);
392
398
  await this.#retireLocalPublication(source);
399
+ if (source === "screen") await this.#retireLocalPublication("screen_audio");
393
400
  if (!this.#replaceMediaConnection) return;
394
401
  const generation = this.#generation;
395
402
  await this.#serializeSDP(async () => {
@@ -408,7 +415,7 @@ var CloudflareSFUClient = class {
408
415
  async #retireUnavailableLocalPublication(state) {
409
416
  const publicationId = state.providerPublicationId;
410
417
  if (!publicationId) return;
411
- const authoritative = await traceReconnect(this.#recordReconnect, "list_publications", () => this.#requireTransport().listPublications());
418
+ const authoritative = await (() => this.#requireTransport().listPublications())();
412
419
  if (authoritative.publications.some((publication) => publication.publicationId === publicationId)) return;
413
420
  if (state.providerPublicationId === publicationId) await this.#retireLocalPublication(state.source);
414
421
  }
@@ -436,8 +443,8 @@ var CloudflareSFUClient = class {
436
443
  const mid = requireTransceiverMid(transceiver);
437
444
  await this.#boundPeerOperation(transceiver.sender.replaceTrack(null));
438
445
  transceiver.stop();
439
- const offer = await traceReconnect(this.#recordReconnect, "create_offer", () => connection.createOffer());
440
- await traceReconnect(this.#recordReconnect, "set_local_description", () => connection.setLocalDescription(offer));
446
+ const offer = await (() => connection.createOffer())();
447
+ await (() => connection.setLocalDescription(offer))();
441
448
  try {
442
449
  const response = await this.#requireTransport().closeTracks({
443
450
  connectionId,
@@ -467,7 +474,6 @@ var CloudflareSFUClient = class {
467
474
  this.#requireActive();
468
475
  const options = "connectionId" in input ? { bootstrap: input } : input;
469
476
  validateBootstrap(options.bootstrap);
470
- recordReconnect(this.#recordReconnect, "media_rebuild_start");
471
477
  const generation = ++this.#generation;
472
478
  const connectionEpoch = ++this.#connectionEpoch;
473
479
  this.#polling = false;
@@ -496,6 +502,7 @@ var CloudflareSFUClient = class {
496
502
  try {
497
503
  await this.#publishPreparedTracks(states, generation);
498
504
  this.#requireGeneration(generation);
505
+ if (this.#remoteRecoveryGeneration !== generation) this.#replacementAttemptedGeneration = null;
499
506
  this.#started = true;
500
507
  this.#setPhase("live", null);
501
508
  this.#schedulePoll(0);
@@ -507,6 +514,7 @@ var CloudflareSFUClient = class {
507
514
  stop() {
508
515
  if (this.#stopped) return;
509
516
  this.#stopped = true;
517
+ this.#subscribedPublicationIds.clear();
510
518
  this.#generation++;
511
519
  this.#connectionEpoch++;
512
520
  this.#clearPoll();
@@ -561,6 +569,7 @@ var CloudflareSFUClient = class {
561
569
  const generation = this.#generation;
562
570
  try {
563
571
  await this.#publishPreparedTracks([state], generation);
572
+ if (this.#remoteRecoveryGeneration !== generation) this.#replacementAttemptedGeneration = null;
564
573
  } catch (error) {
565
574
  state.desiredEnabled = false;
566
575
  state.enabled = false;
@@ -584,7 +593,6 @@ var CloudflareSFUClient = class {
584
593
  if (states.length === 0) return;
585
594
  await this.#serializeSDP(async () => {
586
595
  const pending = await this.#prepareConnectionForPublication(states, generation);
587
- this.#replacementAttemptedGeneration = null;
588
596
  try {
589
597
  await this.#publishPreparedTracksSerialized(pending, generation, this.#connection, this.#bootstrap.connectionId);
590
598
  } catch (error) {
@@ -604,7 +612,7 @@ var CloudflareSFUClient = class {
604
612
  await this.#replaceDormantConnectionBeforeNegotiation(generation);
605
613
  return states;
606
614
  }
607
- const authoritative = await traceReconnect(this.#recordReconnect, "list_publications", () => this.#requireTransport().listPublications());
615
+ const authoritative = await (() => this.#requireTransport().listPublications())();
608
616
  this.#pauseUnavailableOtherSources(authoritative.publications, states);
609
617
  this.#replacementAttemptedGeneration = null;
610
618
  await this.#replaceMediaConnectionForRecovery(generation);
@@ -668,8 +676,8 @@ var CloudflareSFUClient = class {
668
676
  async #negotiateLocalPublications(connection, connectionId, publications, generation) {
669
677
  let offer;
670
678
  try {
671
- offer = await traceReconnect(this.#recordReconnect, "create_offer", () => connection.createOffer());
672
- await traceReconnect(this.#recordReconnect, "set_local_description", () => connection.setLocalDescription(offer));
679
+ offer = await (() => connection.createOffer())();
680
+ await (() => connection.setLocalDescription(offer))();
673
681
  } catch (error) {
674
682
  const cameras = publications.filter(({ state, transceiver }) => state.source === "camera" && transceiver.sender.getParameters().encodings.length > 1);
675
683
  if (!simulcastUnsupported(error) || cameras.length === 0) throw error;
@@ -681,8 +689,8 @@ var CloudflareSFUClient = class {
681
689
  publication.transceiver = connection.addTransceiver(publication.state.track, { direction: "sendonly" });
682
690
  publication.state.transceiver = publication.transceiver;
683
691
  }
684
- offer = await traceReconnect(this.#recordReconnect, "create_offer", () => connection.createOffer());
685
- await traceReconnect(this.#recordReconnect, "set_local_description", () => connection.setLocalDescription(offer));
692
+ offer = await (() => connection.createOffer())();
693
+ await (() => connection.setLocalDescription(offer))();
686
694
  }
687
695
  const tracks = publications.map(
688
696
  ({ state, transceiver, trackName }) => ({
@@ -692,7 +700,7 @@ var CloudflareSFUClient = class {
692
700
  source: state.source
693
701
  })
694
702
  );
695
- const response = await traceReconnect(this.#recordReconnect, "publish_tracks", () => this.#requireTransport().addTracks({ connectionId, ...providerDescription(requireDescription(offer)), tracks }));
703
+ const response = await (() => this.#requireTransport().addTracks({ connectionId, ...providerDescription(requireDescription(offer)), tracks }))();
696
704
  this.#requireGeneration(generation);
697
705
  await this.#applyProviderDescription(response, connection);
698
706
  return response;
@@ -738,10 +746,9 @@ var CloudflareSFUClient = class {
738
746
  }
739
747
  }
740
748
  async #reconcileRemotePublications(authoritative, generation) {
741
- const cursor = this.#validatedRemotePublicationCursor(authoritative);
749
+ const cursor = this.#nextRemotePublicationCursor(authoritative);
742
750
  if (cursor === null) return;
743
- const ordering = comparePublicationCursor(this.#cursor, cursor);
744
- if (ordering === "stale" || ordering === "same" && !this.#remotePullIncomplete) return;
751
+ const participantRevision = this.#remoteParticipantRevision;
745
752
  const desired = this.#desiredRemotePublications(authoritative, cursor);
746
753
  const toPull = this.#pendingRemotePulls(desired);
747
754
  this.#pollFailedPull = true;
@@ -753,8 +760,13 @@ var CloudflareSFUClient = class {
753
760
  this.#remoteTracks.clear();
754
761
  for (const [key, publication] of next) this.#remoteTracks.set(key, publication);
755
762
  this.#cursor = cursor;
756
- this.#remotePullIncomplete = [...desired].some(([key, publication]) => next.get(key)?.publicationId !== publication.publicationId);
757
- for (const publication of pulled) this.#invokeListener(() => this.#onRemoteTrack?.(publication));
763
+ this.#remotePullIncomplete = participantRevision !== this.#remoteParticipantRevision || next.size !== desired.size;
764
+ if (!this.#remotePullIncomplete) this.#remoteRecoveryGeneration = null;
765
+ if (!this.#remotePullIncomplete && this.#hasLiveRemoteTracks()) this.#replacementAttemptedGeneration = null;
766
+ for (const publication of pulled) {
767
+ this.#subscribedPublicationIds.add(publication.publicationId);
768
+ this.#invokeListener(() => this.#onRemoteTrack?.(publication));
769
+ }
758
770
  this.#publishSnapshot();
759
771
  this.#emitRemote();
760
772
  }
@@ -763,31 +775,40 @@ var CloudflareSFUClient = class {
763
775
  for (const publicationId of this.#remotePullRetryAfter.keys()) {
764
776
  if (!desiredIds.has(publicationId)) this.#remotePullRetryAfter.delete(publicationId);
765
777
  }
778
+ for (const publicationId of this.#subscribedPublicationIds) {
779
+ if (!desiredIds.has(publicationId)) this.#subscribedPublicationIds.delete(publicationId);
780
+ }
766
781
  const now = Date.now();
767
782
  return [...desired].filter(([key, publication]) => {
768
783
  if (this.#remoteTracks.get(key)?.publicationId === publication.publicationId) return false;
769
784
  const remaining = (this.#remotePullRetryAfter.get(publication.publicationId) ?? 0) - now;
770
- if (remaining > 0) recordReconnect(this.#recordReconnect, "remote_pull_deferred", { remaining_ms: remaining, source: publication.source });
771
785
  return remaining <= 0;
772
786
  }).map(([, publication]) => publication);
773
787
  }
774
- #validatedRemotePublicationCursor(authoritative) {
788
+ #nextRemotePublicationCursor(authoritative) {
775
789
  if (this.#cursor?.signature === INVALID_PUBLICATION_SIGNATURE && this.#cursor.incarnation === authoritative.incarnation && this.#cursor.sequence === authoritative.sequence) return null;
790
+ let cursor;
776
791
  try {
777
- return validatePublicationSnapshot(authoritative);
792
+ cursor = validatePublicationSnapshot(authoritative);
778
793
  } catch (error) {
779
794
  this.#quarantineInvalidRemotePublicationCursor(authoritative);
780
795
  throw error;
781
796
  }
797
+ const ordering = comparePublicationCursor(this.#cursor, cursor);
798
+ return ordering === "stale" || ordering === "same" && !this.#remotePullIncomplete ? null : cursor;
782
799
  }
783
800
  #desiredRemotePublications(authoritative, cursor) {
784
801
  try {
785
- return desiredRemotePublications(authoritative.publications, this.#participantId);
802
+ const publications = authoritative.publications.filter((publication) => this.#canSubscribeToRemotePublication(publication));
803
+ return desiredRemotePublications(publications, this.#participantId);
786
804
  } catch (error) {
787
805
  this.#observeRemotePublicationCursor(cursor);
788
806
  throw error;
789
807
  }
790
808
  }
809
+ #canSubscribeToRemotePublication(publication) {
810
+ return this.#remoteParticipantIds === null || this.#remoteParticipantIds.has(publication.participantId) || this.#subscribedPublicationIds.has(publication.publicationId);
811
+ }
791
812
  async #pullWithRecovery(publications, cursor, generation) {
792
813
  try {
793
814
  return await this.#pull(publications, generation);
@@ -801,12 +822,13 @@ var CloudflareSFUClient = class {
801
822
  }
802
823
  }
803
824
  #canReplaceConnectionAfterRemotePull(error, generation) {
804
- return error instanceof CloudflareSFUError && error.code === "signaling_failed" && !this.#hasLiveRemoteTracks() && this.#replaceMediaConnection !== void 0 && this.#replacementAttemptedGeneration !== generation;
825
+ return this.#isRetryableConnectionFailure(error) && !this.#hasLiveRemoteTracks() && this.#replaceMediaConnection !== void 0 && this.#replacementAttemptedGeneration !== generation;
805
826
  }
806
827
  #hasLiveRemoteTracks() {
807
828
  return [...this.#remoteTracks.values()].some((publication) => publication.track.readyState === "live");
808
829
  }
809
830
  async #retryRemotePullOnReplacement(publications, cursor, generation) {
831
+ this.#remoteRecoveryGeneration = generation;
810
832
  try {
811
833
  await this.#replaceMediaConnectionForRecovery(generation);
812
834
  await this.#republishPreparedTracksAfterRecovery(generation);
@@ -818,6 +840,44 @@ var CloudflareSFUClient = class {
818
840
  }
819
841
  }
820
842
  async #pull(publications, generation) {
843
+ const eligible = publications.filter((publication) => this.#canSubscribeToRemotePublication(publication));
844
+ try {
845
+ return await this.#pullBatch(eligible, generation);
846
+ } catch (error) {
847
+ this.#requireGeneration(generation);
848
+ if (eligible.length <= 1 || !retryableRemotePull(error) || isRateLimited(error) || this.#canReplaceConnectionAfterRemotePull(error, generation) || error instanceof CloudflareSFUError && (error.options.status === 404 || error.options.status === 410)) {
849
+ this.#deferRemotePulls(eligible, error);
850
+ throw error;
851
+ }
852
+ }
853
+ return this.#pullIndividually(eligible, generation);
854
+ }
855
+ async #pullIndividually(eligible, generation) {
856
+ const pulled = [];
857
+ let failure;
858
+ for (const [index, publication] of eligible.entries()) {
859
+ if (!this.#canSubscribeToRemotePublication(publication)) continue;
860
+ try {
861
+ pulled.push(...await this.#pullBatch([publication], generation));
862
+ } catch (error) {
863
+ this.#requireGeneration(generation);
864
+ this.#deferRemotePulls([publication], error);
865
+ this.#reportError(error);
866
+ if (failure === void 0 || retryableRemotePull(error)) failure = error;
867
+ if (isRateLimited(error)) {
868
+ this.#deferRemotePulls(eligible.slice(index + 1), error);
869
+ break;
870
+ }
871
+ }
872
+ }
873
+ if (failure && pulled.length === 0) throw failure;
874
+ return pulled;
875
+ }
876
+ #deferRemotePulls(publications, error) {
877
+ const retryAfter = retryableRemotePull(error) ? Date.now() + 15e3 : Number.POSITIVE_INFINITY;
878
+ for (const publication of publications) this.#remotePullRetryAfter.set(publication.publicationId, retryAfter);
879
+ }
880
+ async #pullBatch(publications, generation) {
821
881
  if (publications.length === 0) return [];
822
882
  return this.#serializeSDP(async () => {
823
883
  const connection = this.#connection;
@@ -841,7 +901,7 @@ var CloudflareSFUClient = class {
841
901
  connection.addEventListener("track", onTrack);
842
902
  try {
843
903
  this.#requireGeneration(generation);
844
- const response = await traceReconnect(this.#recordReconnect, "pull_tracks", () => this.#requireTransport().addTracks({ connectionId, tracks: requested, allowPartialRemoteTracks: true }));
904
+ const response = await (() => this.#requireTransport().addTracks({ connectionId, tracks: requested, allowPartialRemoteTracks: true }))();
845
905
  this.#requireGeneration(generation);
846
906
  this.#recordRemotePullErrors(publications, response.trackErrors ?? []);
847
907
  const responseTracks = response.tracks ?? [];
@@ -851,7 +911,7 @@ var CloudflareSFUClient = class {
851
911
  if (matched.length === 0) return [];
852
912
  await this.#waitForConnection(connection, generation);
853
913
  this.#negotiatedGeneration = generation;
854
- await traceReconnect(this.#recordReconnect, "remote_track_arrival", () => waitFor(() => responseTracks.every((track) => track.mid !== void 0 && received.has(track.mid)), 5e3));
914
+ await (() => waitFor(() => responseTracks.every((track) => track.mid !== void 0 && received.has(track.mid)), 5e3))();
855
915
  this.#requireGeneration(generation);
856
916
  return matched.map(({ publication, mid }) => {
857
917
  const track = received.get(mid);
@@ -876,26 +936,24 @@ var CloudflareSFUClient = class {
876
936
  for (const failure of failures) {
877
937
  const publication = requested.get(`${failure.connectionId}\0${failure.trackName}`);
878
938
  if (!publication) throw new CloudflareSFUError("Cloudflare SFU returned an unrequested remote track error", "invalid_publication");
879
- const delay = 750;
939
+ const delay = 15e3;
880
940
  this.#remotePullRetryAfter.set(publication.publicationId, Date.now() + delay);
881
- recordReconnect(this.#recordReconnect, "remote_pull_backoff", { delay_ms: delay, retry_kind: failure.code === "empty_track_error" ? "empty_track" : "provider_error", source: publication.source });
882
941
  this.#reportError(new CloudflareSFUError(`Cloudflare SFU remote track failed: ${failure.code}`, "media_failed", { providerCode: failure.code }));
883
942
  }
884
943
  }
885
944
  async #completeRenegotiation(response, connection, connectionId, generation) {
886
945
  if (!response.requiresImmediateRenegotiation) return;
887
946
  await this.#applyProviderDescription(response, connection);
888
- const answer = await traceReconnect(this.#recordReconnect, "create_answer", () => connection.createAnswer());
889
- await traceReconnect(this.#recordReconnect, "set_local_answer", () => connection.setLocalDescription(answer));
890
- await traceReconnect(this.#recordReconnect, "renegotiate", () => this.#requireTransport().renegotiate({ connectionId, ...providerDescription(requireDescription(answer)) }));
947
+ const answer = await (() => connection.createAnswer())();
948
+ await (() => connection.setLocalDescription(answer))();
949
+ await (() => this.#requireTransport().renegotiate({ connectionId, ...providerDescription(requireDescription(answer)) }))();
891
950
  this.#requireGeneration(generation);
892
951
  }
893
952
  async #applyProviderDescription(response, connection = this.#connection) {
894
- await traceReconnect(this.#recordReconnect, "set_remote_description", () => connection.setRemoteDescription(requireSFUDescription(response.sessionDescription)));
953
+ await (() => connection.setRemoteDescription(requireSFUDescription(response.sessionDescription)))();
895
954
  }
896
955
  #serializeSDP(operation) {
897
956
  const generation = this.#generation;
898
- const queuedAt = performance.now();
899
957
  let expired = false;
900
958
  let timer;
901
959
  const timeout = new CloudflareSFUError("Cloudflare SFU negotiation timed out. Try again.", "negotiation_timeout");
@@ -908,7 +966,6 @@ var CloudflareSFUClient = class {
908
966
  });
909
967
  const run = () => {
910
968
  if (expired || generation !== this.#generation) throw timeout;
911
- recordReconnect(this.#recordReconnect, "sdp_queue", { duration_ms: performance.now() - queuedAt });
912
969
  return operation();
913
970
  };
914
971
  const pending = this.#sdpTail.then(run, run);
@@ -949,18 +1006,14 @@ var CloudflareSFUClient = class {
949
1006
  this.#setFailure(error, "media_failed");
950
1007
  }
951
1008
  #waitForConnection(connection, generation) {
952
- return traceReconnect(
953
- this.#recordReconnect,
954
- "connection_ready",
955
- () => waitFor(
956
- () => {
957
- this.#requireGeneration(generation);
958
- return connectionIsLive(connection);
959
- },
960
- CONNECTION_TIMEOUT_MS,
961
- "Timed out waiting for the Cloudflare SFU peer connection"
962
- )
963
- );
1009
+ return (() => waitFor(
1010
+ () => {
1011
+ this.#requireGeneration(generation);
1012
+ return connectionIsLive(connection);
1013
+ },
1014
+ CONNECTION_TIMEOUT_MS,
1015
+ "Timed out waiting for the Cloudflare SFU peer connection"
1016
+ ))();
964
1017
  }
965
1018
  #cameraSimulcastSender(state) {
966
1019
  if (!state?.enabled) return void 0;
@@ -1023,84 +1076,16 @@ var CloudflareSFUClient = class {
1023
1076
  };
1024
1077
  const capture = () => {
1025
1078
  if (disposed || generation !== this.#generation || connectionEpoch !== this.#connectionEpoch || this.#stopped) return;
1026
- recordReconnect(this.#recordReconnect, "rtc_state", { connection_state: connection.connectionState, ice_connection_state: connection.iceConnectionState, signaling_state: connection.signalingState });
1027
1079
  observe();
1028
- const recorder = this.#onRtcSummary;
1029
- if (recorder) {
1030
- let stats;
1031
- try {
1032
- stats = Promise.resolve(connection.getStats());
1033
- } catch {
1034
- stats = Promise.reject(new Error("RTC stats are unavailable"));
1035
- }
1036
- void stats.then((report) => {
1037
- if (disposed || generation !== this.#generation || connectionEpoch !== this.#connectionEpoch || this.#stopped) return;
1038
- recorder(rtcConnectionState(connection), rtcStats(report));
1039
- }).catch(() => void 0);
1040
- }
1041
1080
  if (connection.connectionState === "closed") dispose();
1042
1081
  };
1043
1082
  this.#disposeConnectionObservation = dispose;
1044
1083
  cameraTimer = globalThis.setTimeout(adaptCamera, 1e3);
1045
- if (this.#recordReconnect) this.#sampleRecoveryTraffic(connection, generation, connectionEpoch);
1046
1084
  connection.addEventListener("connectionstatechange", capture);
1047
1085
  connection.addEventListener("iceconnectionstatechange", capture);
1048
1086
  connection.addEventListener("signalingstatechange", capture);
1049
1087
  capture();
1050
1088
  }
1051
- #sampleRecoveryTraffic(connection, generation, connectionEpoch) {
1052
- const traffic = /* @__PURE__ */ new Map();
1053
- let dtlsState;
1054
- const current = () => generation === this.#generation && connectionEpoch === this.#connectionEpoch && !this.#stopped && connection.connectionState !== "closed" && connection.connectionState !== "failed";
1055
- const sample = async () => {
1056
- if (!current()) return;
1057
- try {
1058
- const report = await connection.getStats();
1059
- if (!current()) return;
1060
- const now = performance.now();
1061
- report.forEach((entry) => {
1062
- if (entry.type === "transport") {
1063
- const nextState = rtcString(entry, "dtlsState");
1064
- if (nextState !== dtlsState) recordReconnect(this.#recordReconnect, "dtls_state", { dtls_state: nextState ?? "unknown" });
1065
- dtlsState = nextState;
1066
- }
1067
- this.#observeRecoveryTraffic(entry, traffic, now);
1068
- });
1069
- } catch {
1070
- if (current()) recordReconnect(this.#recordReconnect, "rtc_stats_unavailable");
1071
- }
1072
- if (current()) globalThis.setTimeout(() => void sample(), 250);
1073
- };
1074
- void sample();
1075
- }
1076
- #observeRecoveryTraffic(entry, traffic, now) {
1077
- if (entry.type !== "inbound-rtp" && entry.type !== "outbound-rtp") return;
1078
- const direction = entry.type === "inbound-rtp" ? "inbound" : "outbound";
1079
- const kind = rtcString(entry, "kind") ?? "unknown";
1080
- const previous = traffic.get(entry.id);
1081
- const next = previous ?? {
1082
- packets: { count: 0, lastProgress: now, stalled: false },
1083
- frames: { count: 0, lastProgress: now, stalled: false }
1084
- };
1085
- const packets = recoveryTrafficCount(entry, direction, "packet");
1086
- const frames = recoveryTrafficCount(entry, direction, "frame");
1087
- this.#observeTrafficCounter(next.packets, { count: packets, now, direction, kind, unit: "packet", existed: previous !== void 0 });
1088
- this.#observeTrafficCounter(next.frames, { count: frames, now, direction, kind, unit: "frame", existed: previous !== void 0 });
1089
- traffic.set(entry.id, next);
1090
- }
1091
- #observeTrafficCounter(progress, sample) {
1092
- const attributes = { direction: sample.direction, kind: sample.kind };
1093
- if (sample.count > progress.count) {
1094
- if (progress.count === 0) recordReconnect(this.#recordReconnect, `first_${sample.unit}`, attributes);
1095
- else if (progress.stalled) recordReconnect(this.#recordReconnect, sample.unit === "packet" ? "rtp_resumed" : "frame_resumed", attributes);
1096
- progress.lastProgress = sample.now;
1097
- progress.stalled = false;
1098
- } else if (trafficStalled(progress, sample)) {
1099
- progress.stalled = true;
1100
- recordReconnect(this.#recordReconnect, sample.unit === "packet" ? "rtp_stall" : "frame_stall", attributes);
1101
- }
1102
- progress.count = sample.count;
1103
- }
1104
1089
  async #replaceDormantConnectionBeforeNegotiation(generation) {
1105
1090
  if (!this.#started || this.#negotiatedGeneration === generation || this.#replacementAttemptedGeneration === generation || !this.#replaceMediaConnection) return;
1106
1091
  await this.#replaceMediaConnectionForRecovery(generation);
@@ -1112,7 +1097,7 @@ var CloudflareSFUClient = class {
1112
1097
  }
1113
1098
  this.#replacementAttemptedGeneration = generation;
1114
1099
  const replaceMediaConnection = this.#replaceMediaConnection;
1115
- const bootstrap = await traceReconnect(this.#recordReconnect, "replace_access", replaceMediaConnection);
1100
+ const bootstrap = await replaceMediaConnection();
1116
1101
  this.#requireGeneration(generation);
1117
1102
  validateBootstrap(bootstrap);
1118
1103
  if (bootstrap.connectionId === this.#bootstrap.connectionId) {
@@ -1316,76 +1301,11 @@ function validateClientOptions(options) {
1316
1301
  throw new CloudflareSFUError("Cloudflare SFU polling interval is invalid", "invalid_bootstrap");
1317
1302
  }
1318
1303
  }
1319
- function rtcConnectionState(connection) {
1320
- return {
1321
- connectionState: connection.connectionState,
1322
- iceConnectionState: connection.iceConnectionState,
1323
- signalingState: connection.signalingState
1324
- };
1325
- }
1326
- function rtcStats(report) {
1327
- const entries = [];
1328
- report.forEach((entry) => {
1329
- if (typeof entry.type !== "string") return;
1330
- entries.push({ type: entry.type, ...rtcTrafficStats(entry), ...rtcQualityStats(entry), ...rtcTransportStats(entry) });
1331
- });
1332
- return entries;
1333
- }
1334
- function rtcTrafficStats(entry) {
1335
- const bytesReceived = rtcNumber(entry, "bytesReceived");
1336
- const bytesSent = rtcNumber(entry, "bytesSent");
1337
- const packetsReceived = rtcNumber(entry, "packetsReceived");
1338
- const packetsSent = rtcNumber(entry, "packetsSent");
1339
- return {
1340
- ...bytesReceived !== void 0 ? { bytesReceived } : {},
1341
- ...bytesSent !== void 0 ? { bytesSent } : {},
1342
- ...packetsReceived !== void 0 ? { packetsReceived } : {},
1343
- ...packetsSent !== void 0 ? { packetsSent } : {}
1344
- };
1345
- }
1346
- function rtcQualityStats(entry) {
1347
- const kind = rtcString(entry, "kind");
1348
- const framesDropped = rtcNumber(entry, "framesDropped");
1349
- const jitter = rtcNumber(entry, "jitter");
1350
- const packetsLost = rtcNumber(entry, "packetsLost");
1351
- const roundTripTime = rtcNumber(entry, "roundTripTime");
1352
- return {
1353
- ...kind !== void 0 ? { kind } : {},
1354
- ...framesDropped !== void 0 ? { framesDropped } : {},
1355
- ...jitter !== void 0 ? { jitter } : {},
1356
- ...packetsLost !== void 0 ? { packetsLost } : {},
1357
- ...roundTripTime !== void 0 ? { roundTripTime } : {}
1358
- };
1359
- }
1360
- function rtcTransportStats(entry) {
1361
- const state = rtcString(entry, "state");
1362
- const selected = rtcBoolean(entry, "selected");
1363
- const nominated = rtcBoolean(entry, "nominated");
1364
- const dtlsState = rtcString(entry, "dtlsState");
1365
- return {
1366
- ...state !== void 0 ? { state } : {},
1367
- ...selected !== void 0 ? { selected } : {},
1368
- ...nominated !== void 0 ? { nominated } : {},
1369
- ...dtlsState !== void 0 ? { dtlsState } : {}
1370
- };
1371
- }
1372
- function rtcString(value, property) {
1373
- const candidate = Reflect.get(value, property);
1374
- return typeof candidate === "string" ? candidate : void 0;
1375
- }
1376
- function rtcNumber(value, property) {
1377
- const candidate = Reflect.get(value, property);
1378
- return typeof candidate === "number" ? candidate : void 0;
1379
- }
1380
- function rtcBoolean(value, property) {
1381
- const candidate = Reflect.get(value, property);
1382
- return typeof candidate === "boolean" ? candidate : void 0;
1383
- }
1384
1304
  function validateBootstrap(bootstrap) {
1385
1305
  if (!bootstrap.connectionId.trim() || !bootstrap.stunServer.trim()) throw new CloudflareSFUError("Cloudflare SFU bootstrap is incomplete", "invalid_bootstrap");
1386
1306
  }
1387
1307
  function validateTrackSource(source, track) {
1388
- const valid = source === "microphone" ? track.kind === "audio" : track.kind === "video";
1308
+ const valid = source === "microphone" || source === "screen_audio" ? track.kind === "audio" : track.kind === "video";
1389
1309
  if (!valid) throw new CloudflareSFUError(`The prepared ${source} track has an incompatible kind`, "media_failed");
1390
1310
  }
1391
1311
  function desiredRemotePublications(publications, participantId) {
@@ -1462,8 +1382,13 @@ function remotePublicationEqual(left, right) {
1462
1382
  function providerDescription(description) {
1463
1383
  return { sessionDescription: description };
1464
1384
  }
1385
+ function isRateLimited(error) {
1386
+ return error instanceof CloudflareSFUError && error.options.status === 429;
1387
+ }
1465
1388
  function retryableRemotePull(error) {
1466
- return error instanceof CloudflareSFUError && ["signaling_failed", "signaling_timeout", "media_failed", "negotiation_timeout"].includes(error.code);
1389
+ if (!(error instanceof CloudflareSFUError)) return false;
1390
+ if (error.code === "signaling_failed") return error.options.retryableConnection === true || error.options.status === 429;
1391
+ return ["signaling_timeout", "media_failed", "negotiation_timeout"].includes(error.code);
1467
1392
  }
1468
1393
  function firefoxCameraSimulcastUnsupported() {
1469
1394
  return typeof navigator !== "undefined" && /\bFirefox\/\d+/i.test(navigator.userAgent);
@@ -1476,13 +1401,6 @@ function mediaTargetFailure(error) {
1476
1401
  const ambiguous = code === "signaling_timeout" || code === "negotiation_timeout";
1477
1402
  return { outcome: ambiguous ? "ambiguous" : "retryable_failure", errorCode: code };
1478
1403
  }
1479
- function recoveryTrafficCount(entry, direction, unit) {
1480
- const property = unit === "packet" ? direction === "inbound" ? "packetsReceived" : "packetsSent" : direction === "inbound" ? "framesDecoded" : "framesEncoded";
1481
- return rtcNumber(entry, property) ?? 0;
1482
- }
1483
- function trafficStalled(progress, sample) {
1484
- return sample.existed && !progress.stalled && sample.now - progress.lastProgress >= 1e3 && (sample.unit === "packet" || progress.count > 0);
1485
- }
1486
1404
 
1487
1405
  // src/media/transport.ts
1488
1406
  var SIGNALING_TIMEOUT_MS = 8e3;
@@ -1501,7 +1419,7 @@ function createCloudflareSFUHTTPTransport(options) {
1501
1419
  const response = await fetch(`${mediaPath}/${path}`, {
1502
1420
  ...init,
1503
1421
  signal,
1504
- headers: { ...options.telemetry ? journeyHeaders(options.telemetry) : {}, Authorization: `Bearer ${token}`, "Content-Type": "application/json", ...init?.headers }
1422
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", ...init?.headers }
1505
1423
  });
1506
1424
  if (!response.ok) {
1507
1425
  throw new CloudflareSFUError(`Chalk SFU signaling failed with HTTP ${response.status}`, "signaling_failed", {
@@ -1578,514 +1496,6 @@ function requireCredential(options) {
1578
1496
  throw new CloudflareSFUError("A media credential provider is required", "signaling_failed");
1579
1497
  }
1580
1498
 
1581
- // src/media/rtk.ts
1582
- var CloudflareRTKError = class extends Error {
1583
- code;
1584
- constructor(message, code) {
1585
- super(message);
1586
- this.name = "CloudflareRTKError";
1587
- this.code = code;
1588
- }
1589
- };
1590
- var EMPTY_LOCAL2 = Object.freeze([]);
1591
- var EMPTY_REMOTE2 = Object.freeze([]);
1592
- var CloudflareRTKClient = class {
1593
- #participantId;
1594
- #onError;
1595
- #onScreenEnded;
1596
- #clientFactory;
1597
- #snapshotListeners = /* @__PURE__ */ new Set();
1598
- #sourceOperations = /* @__PURE__ */ new Map();
1599
- #generationInvalidators = /* @__PURE__ */ new Set();
1600
- #connection = null;
1601
- #localTracks = /* @__PURE__ */ new Map();
1602
- #connectionUnsubscribers = [];
1603
- #participantUnsubscribers = /* @__PURE__ */ new Map();
1604
- #snapshot;
1605
- #stopped = false;
1606
- #generation = 0;
1607
- #screenDisableRequested = false;
1608
- #initialAuthToken;
1609
- constructor(options) {
1610
- if (!options.authToken.trim()) throw new CloudflareRTKError("A RealtimeKit auth token is required", "invalid_client");
1611
- if (!options.participantId.trim()) throw new CloudflareRTKError("A participant ID is required", "invalid_participant");
1612
- this.#participantId = options.participantId;
1613
- this.#onError = options.onError;
1614
- this.#onScreenEnded = options.onScreenEnded;
1615
- this.#clientFactory = options.clientFactory ?? defaultClientFactory;
1616
- this.#snapshot = freezeSnapshot2({
1617
- connection: { phase: "idle", peerConnectionState: null, iceConnectionState: null },
1618
- cursor: null,
1619
- localTracks: EMPTY_LOCAL2,
1620
- remoteTracks: EMPTY_REMOTE2,
1621
- failure: null
1622
- });
1623
- this.#initialAuthToken = options.authToken;
1624
- }
1625
- getSnapshot() {
1626
- return this.#snapshot;
1627
- }
1628
- subscribe(listener) {
1629
- return subscribeSnapshot(this.#snapshotListeners, listener);
1630
- }
1631
- prepareLocalTrack(source, track) {
1632
- this.#requireStartable();
1633
- validateTrack(source, track);
1634
- if (this.#localTracks.has(source)) throw new CloudflareRTKError(`A ${source} track is already prepared`, "media_failed");
1635
- const endedListener = source === "screen" ? () => this.#onScreenEnded?.() : null;
1636
- if (endedListener) track.addEventListener("ended", endedListener);
1637
- this.#localTracks.set(source, { source, track, enabled: false, endedListener });
1638
- this.#publishSnapshot();
1639
- }
1640
- async clearPreparedLocalTrack(source) {
1641
- const state = this.#localTracks.get(source);
1642
- if (!state) return;
1643
- const connection = this.#connection;
1644
- if (state.endedListener) state.track.removeEventListener("ended", state.endedListener);
1645
- this.#localTracks.delete(source);
1646
- const actions = connection ? this.#sourceActions(state, connection) : null;
1647
- const cleanup = actions?.enabled && state.enabled ? this.#queueSourceOperation(source, () => connection === this.#connection ? actions.disable() : Promise.resolve()) : Promise.resolve();
1648
- this.#publishSnapshot();
1649
- try {
1650
- await cleanup;
1651
- } catch (error) {
1652
- if (!isStaleGeneration(error)) throw error;
1653
- }
1654
- }
1655
- async start(localMedia) {
1656
- if (this.#snapshot.connection.phase === "live") return;
1657
- this.#requireStartable();
1658
- const generation = this.#advanceGeneration();
1659
- this.#setPhase("connecting", null);
1660
- try {
1661
- const tracks = localMedia.getTracks().filter((track) => track.kind === "audio" || track.kind === "video");
1662
- for (const track of tracks) {
1663
- const source = track.kind === "audio" ? "microphone" : "camera";
1664
- if (!this.#localTracks.has(source)) this.#localTracks.set(source, { source, track, enabled: false, endedListener: null });
1665
- }
1666
- if (!await this.#openConnection(this.#initialAuthToken, generation)) return;
1667
- await this.#restoreLocalTracks(generation, true);
1668
- } catch (error) {
1669
- this.#failCurrentGeneration(generation, error);
1670
- throw error;
1671
- }
1672
- }
1673
- async setLocalPublicationTarget(target) {
1674
- const resolved = resolveMediaTarget(this.#participantId, this.#stopped, this.#localTracks, target);
1675
- if (resolved.kind === "result") return resolved.result;
1676
- const generation = this.#generation;
1677
- try {
1678
- return await this.#queueSourceOperation(target.source, () => this.#applyLocalTarget(target, generation));
1679
- } catch (error) {
1680
- return { outcome: "retryable_failure", errorCode: error instanceof CloudflareRTKError ? error.code : "media_failed" };
1681
- }
1682
- }
1683
- async #queueSourceOperation(source, apply) {
1684
- const previous = this.#sourceOperations.get(source) ?? Promise.resolve();
1685
- const generation = this.#generation;
1686
- let invalidate = () => {
1687
- };
1688
- const retired = new Promise((_resolve, reject) => {
1689
- invalidate = () => reject(new CloudflareRTKError("The media operation belongs to a retired connection", "stale_generation"));
1690
- this.#generationInvalidators.add(invalidate);
1691
- });
1692
- const operation = Promise.race([
1693
- previous.catch(() => void 0).then(() => {
1694
- if (!this.#isCurrentGeneration(generation)) throw new CloudflareRTKError("The queued media operation belongs to a retired connection", "stale_generation");
1695
- return apply();
1696
- }),
1697
- retired
1698
- ]);
1699
- this.#sourceOperations.set(source, operation);
1700
- try {
1701
- return await operation;
1702
- } finally {
1703
- this.#generationInvalidators.delete(invalidate);
1704
- if (this.#sourceOperations.get(source) === operation) this.#sourceOperations.delete(source);
1705
- }
1706
- }
1707
- async #applyLocalTarget(target, generation) {
1708
- if (!this.#isCurrentGeneration(generation)) return { outcome: "retryable_failure", errorCode: "stale_generation" };
1709
- const resolved = resolveMediaTarget(this.#participantId, this.#stopped, this.#localTracks, target);
1710
- if (resolved.kind === "result") return resolved.result;
1711
- const state = resolved.value;
1712
- try {
1713
- if (!this.#connection) throw new CloudflareRTKError("The RealtimeKit connection is recovering", "stale_generation");
1714
- if (state.enabled === target.enabled) return { outcome: "satisfied", errorCode: null };
1715
- await this.#setSourceEnabled(state, target.enabled);
1716
- return { outcome: "confirmed", errorCode: null };
1717
- } catch (error) {
1718
- this.#reportError(error);
1719
- return { outcome: "retryable_failure", errorCode: error instanceof CloudflareRTKError ? error.code : "media_failed" };
1720
- }
1721
- }
1722
- observeLocalPublications(listener) {
1723
- return observePublications(this.#snapshotListeners, listener, () => this.#projectLocalPublications());
1724
- }
1725
- observeRemotePublications(listener) {
1726
- return observePublications(this.#snapshotListeners, listener, () => this.#projectRemotePublications());
1727
- }
1728
- async restart(input) {
1729
- if (!isRTKAccess(input)) throw new CloudflareRTKError("The RealtimeKit adapter requires a Cloudflare RealtimeKit access grant", "invalid_client");
1730
- if (this.#stopped) throw new CloudflareRTKError("The RealtimeKit media client has stopped", "media_stopped");
1731
- const generation = this.#advanceGeneration();
1732
- this.#setPhase("recovering", null);
1733
- try {
1734
- await this.#closeConnection();
1735
- if (!this.#isCurrentGeneration(generation)) return;
1736
- if (!await this.#openConnection(input.clientPayload.token, generation)) return;
1737
- await this.#restoreLocalTracks(generation, false);
1738
- } catch (error) {
1739
- this.#failCurrentGeneration(generation, error);
1740
- throw error;
1741
- }
1742
- }
1743
- stop() {
1744
- if (this.#stopped) return;
1745
- this.#stopped = true;
1746
- this.#advanceGeneration();
1747
- const leave = this.#closeConnection();
1748
- void leave.catch((error) => this.#reportError(error));
1749
- for (const state of this.#localTracks.values()) if (state.endedListener) state.track.removeEventListener("ended", state.endedListener);
1750
- this.#localTracks.clear();
1751
- this.#setPhase("stopped", null);
1752
- }
1753
- #isCurrentGeneration(generation) {
1754
- return !this.#stopped && generation === this.#generation;
1755
- }
1756
- #advanceGeneration() {
1757
- const generation = ++this.#generation;
1758
- this.#sourceOperations.clear();
1759
- for (const invalidate of this.#generationInvalidators) invalidate();
1760
- this.#generationInvalidators.clear();
1761
- return generation;
1762
- }
1763
- async #restoreLocalTracks(generation, initial) {
1764
- for (const state of this.#localTracks.values()) {
1765
- if (!this.#isCurrentGeneration(generation)) return;
1766
- const enable = initial ? state.source !== "screen" : state.enabled;
1767
- if (enable) {
1768
- await this.#queueSourceOperation(state.source, async () => {
1769
- if (!this.#isCurrentGeneration(generation) || this.#localTracks.get(state.source) !== state || !initial && !state.enabled) return;
1770
- await this.#setSourceEnabled(state, true);
1771
- }).catch((error) => {
1772
- if (!this.#isCurrentGeneration(generation)) return;
1773
- if (isStaleGeneration(error) && this.#localTracks.get(state.source) !== state) return;
1774
- throw error;
1775
- });
1776
- }
1777
- }
1778
- if (this.#isCurrentGeneration(generation)) this.#setPhase("live", null);
1779
- }
1780
- #failCurrentGeneration(generation, error) {
1781
- if (!this.#isCurrentGeneration(generation)) return;
1782
- this.#setFailure(error);
1783
- this.#reportError(error);
1784
- }
1785
- async #openConnection(authToken, generation) {
1786
- const connection = await this.#clientFactory({ authToken, onError: (error) => this.#reportError(error) });
1787
- if (!this.#isCurrentGeneration(generation)) {
1788
- await connection.leave();
1789
- return false;
1790
- }
1791
- this.#connection = connection;
1792
- this.#bindConnection(connection);
1793
- await connection.join();
1794
- if (!this.#isCurrentGeneration(generation)) {
1795
- await connection.leave();
1796
- return false;
1797
- }
1798
- return true;
1799
- }
1800
- async #closeConnection() {
1801
- const connection = this.#connection;
1802
- this.#connection = null;
1803
- this.#unbindConnection();
1804
- if (connection) await connection.leave();
1805
- }
1806
- #bindConnection(connection) {
1807
- const selfAudio = connection.self.onAudioUpdate(() => this.#syncLocalState("microphone"));
1808
- const selfVideo = connection.self.onVideoUpdate(() => this.#syncLocalState("camera"));
1809
- const selfScreen = connection.self.onScreenShareUpdate((payload) => {
1810
- this.#syncLocalState("screen");
1811
- if (!payload.screenShareEnabled && !this.#screenDisableRequested) this.#onScreenEnded?.();
1812
- this.#screenDisableRequested = false;
1813
- });
1814
- const connectionLeft = connection.self.onLeft(() => {
1815
- if (this.#stopped) return;
1816
- const error = new CloudflareRTKError("The RealtimeKit connection ended unexpectedly", "media_failed");
1817
- this.#setFailure(error);
1818
- this.#reportError(error);
1819
- });
1820
- for (const participant of connection.participants.joined.list()) this.#bindParticipant(participant);
1821
- const participantJoined = connection.participants.joined.onJoined((participant) => {
1822
- this.#bindParticipant(participant);
1823
- this.#publishSnapshot();
1824
- });
1825
- const participantLeft = connection.participants.joined.onLeft((participant) => {
1826
- this.#unbindParticipant(participant.id);
1827
- this.#publishSnapshot();
1828
- });
1829
- this.#connectionUnsubscribers = [selfAudio, selfVideo, selfScreen, connectionLeft, participantJoined, participantLeft];
1830
- }
1831
- #unbindConnection() {
1832
- for (const unsubscribe of this.#connectionUnsubscribers) unsubscribe();
1833
- this.#connectionUnsubscribers = [];
1834
- for (const unsubscribers of this.#participantUnsubscribers.values()) for (const unsubscribe of unsubscribers) unsubscribe();
1835
- this.#participantUnsubscribers.clear();
1836
- }
1837
- #bindParticipant(participant) {
1838
- if (this.#participantUnsubscribers.has(participant.id)) return;
1839
- const unsubscribers = [participant.onAudioUpdate?.(() => this.#publishSnapshot()), participant.onVideoUpdate?.(() => this.#publishSnapshot()), participant.onScreenShareUpdate?.(() => this.#publishSnapshot())].filter((unsubscribe) => unsubscribe !== void 0);
1840
- this.#participantUnsubscribers.set(participant.id, unsubscribers);
1841
- }
1842
- #unbindParticipant(participantId) {
1843
- const unsubscribers = this.#participantUnsubscribers.get(participantId);
1844
- if (!unsubscribers) return;
1845
- for (const unsubscribe of unsubscribers) unsubscribe();
1846
- this.#participantUnsubscribers.delete(participantId);
1847
- }
1848
- async #setSourceEnabled(state, enabled) {
1849
- const connection = this.#connection;
1850
- const generation = this.#generation;
1851
- if (!connection) throw new CloudflareRTKError("The RealtimeKit connection is not active", "media_stopped");
1852
- const actions = this.#sourceActions(state, connection);
1853
- if (state.source === "screen") this.#screenDisableRequested = !enabled;
1854
- await actions[enabled ? "enable" : "disable"]();
1855
- try {
1856
- this.#requireCurrentSource(state, connection, generation);
1857
- } catch (error) {
1858
- if (enabled)
1859
- await actions.disable().catch((cause) => {
1860
- this.#failCurrentGeneration(generation, cause);
1861
- throw cause;
1862
- });
1863
- throw error;
1864
- }
1865
- state.enabled = enabled;
1866
- state.track.enabled = enabled;
1867
- this.#publishSnapshot();
1868
- }
1869
- #sourceActions(state, connection) {
1870
- return {
1871
- microphone: { enabled: connection.self.audioEnabled, enable: () => connection.self.enableAudio(state.track), disable: () => connection.self.disableAudio() },
1872
- camera: { enabled: connection.self.videoEnabled, enable: () => connection.self.enableVideo(state.track), disable: () => connection.self.disableVideo() },
1873
- screen: {
1874
- enabled: connection.self.screenShareEnabled,
1875
- enable: () => connection.self.enableScreenShare(),
1876
- disable: () => {
1877
- if (connection === this.#connection) this.#screenDisableRequested = true;
1878
- return connection.self.disableScreenShare();
1879
- }
1880
- }
1881
- }[state.source];
1882
- }
1883
- #requireCurrentSource(state, connection, generation) {
1884
- if (!this.#isCurrentGeneration(generation) || connection !== this.#connection || this.#localTracks.get(state.source) !== state) {
1885
- throw new CloudflareRTKError("The local media target belongs to a replaced connection or source", "stale_generation");
1886
- }
1887
- }
1888
- #syncLocalState(source) {
1889
- const state = this.#localTracks.get(source);
1890
- const connection = this.#connection;
1891
- if (!state || !connection) return;
1892
- state.enabled = source === "microphone" ? connection.self.audioEnabled : source === "camera" ? connection.self.videoEnabled : connection.self.screenShareEnabled;
1893
- state.track.enabled = state.enabled;
1894
- this.#publishSnapshot();
1895
- }
1896
- #publishSnapshot() {
1897
- this.#snapshot = freezeSnapshot2({ ...this.#snapshot, localTracks: this.#projectLocalTracks(), remoteTracks: this.#projectRemoteTracks() });
1898
- this.#notifyListeners();
1899
- }
1900
- #projectLocalTracks() {
1901
- return Object.freeze([...this.#localTracks.values()].map((state) => ({ source: state.source, enabled: state.enabled, publicationId: `${this.#participantId}:${state.source}`, track: state.track })));
1902
- }
1903
- #projectLocalPublications() {
1904
- return Object.freeze(this.#projectLocalTracks().map((track) => ({ participantId: this.#participantId, source: track.source, enabled: track.enabled, publicationId: track.publicationId })));
1905
- }
1906
- #projectRemotePublications() {
1907
- return Object.freeze(this.#projectRemoteTracks().map((track) => ({ participantId: track.participantId, source: track.source, enabled: true, publicationId: track.publicationId })));
1908
- }
1909
- #projectRemoteTracks() {
1910
- return projectRemoteTracks(this.#connection?.participants.joined.list() ?? []);
1911
- }
1912
- #setPhase(phase, failure) {
1913
- this.#snapshot = freezeSnapshot2({ ...this.#snapshot, connection: { phase, peerConnectionState: null, iceConnectionState: null }, failure });
1914
- this.#notifyListeners();
1915
- }
1916
- #setFailure(error) {
1917
- this.#setPhase("failed", { code: "media_failed", recoverable: true });
1918
- if (!(error instanceof CloudflareRTKError)) this.#reportError(error);
1919
- }
1920
- #requireStartable() {
1921
- if (this.#stopped) throw new CloudflareRTKError("The RealtimeKit media client has stopped", "media_stopped");
1922
- }
1923
- #reportError(error) {
1924
- try {
1925
- this.#onError?.(error);
1926
- } catch {
1927
- }
1928
- }
1929
- #notifyListeners() {
1930
- for (const listener of this.#snapshotListeners) {
1931
- try {
1932
- listener();
1933
- } catch (error) {
1934
- this.#reportError(error);
1935
- }
1936
- }
1937
- }
1938
- };
1939
- function projectRemoteTracks(participants) {
1940
- return Object.freeze(participants.flatMap(remoteTracksForParticipant));
1941
- }
1942
- function remoteTracksForParticipant(participant) {
1943
- const participantId = participantIdentifier(participant);
1944
- if (!participantId) return [];
1945
- const publications = [];
1946
- addRemotePublication(publications, participant, participantId, "microphone", participant.audioEnabled ? participant.audioTrack : null);
1947
- addRemotePublication(publications, participant, participantId, "camera", participant.videoEnabled ? participant.videoTrack : null);
1948
- addRemotePublication(publications, participant, participantId, "screen", participant.screenShareEnabled ? participant.screenShareTracks.video ?? null : null);
1949
- return publications;
1950
- }
1951
- function participantIdentifier(participant) {
1952
- return participant.customParticipantId?.trim() || participant.userId.trim() || participant.id.trim();
1953
- }
1954
- function addRemotePublication(publications, participant, participantId, source, track) {
1955
- if (!track) return;
1956
- publications.push({ participantId, source, publicationId: `${participant.id}:${source}`, track });
1957
- }
1958
- function validateTrack(source, track) {
1959
- const expectedKind = source === "microphone" ? "audio" : "video";
1960
- if (track.kind !== expectedKind) throw new CloudflareRTKError(`A ${source} track must be ${expectedKind}`, "invalid_target");
1961
- }
1962
- function isRTKAccess(value) {
1963
- return value.provider === "cloudflare_rtk";
1964
- }
1965
- function freezeSnapshot2(snapshot) {
1966
- const failure = snapshot.failure ? Object.freeze(snapshot.failure) : null;
1967
- return Object.freeze({
1968
- ...snapshot,
1969
- connection: Object.freeze(snapshot.connection),
1970
- localTracks: Object.freeze(snapshot.localTracks.map((track) => Object.freeze(track))),
1971
- remoteTracks: Object.freeze(snapshot.remoteTracks.map((track) => Object.freeze(track))),
1972
- failure
1973
- });
1974
- }
1975
- async function defaultClientFactory(input) {
1976
- const { default: RealtimeKitClient } = await import("@cloudflare/realtimekit");
1977
- const client = await RealtimeKitClient.init({
1978
- authToken: input.authToken,
1979
- defaults: { audio: false, video: false },
1980
- onError: input.onError
1981
- });
1982
- return adaptRealtimeKitClient(client);
1983
- }
1984
- function adaptRealtimeKitClient(client) {
1985
- const self = client.self;
1986
- return {
1987
- join: () => client.join(),
1988
- leave: () => client.leave(),
1989
- self: {
1990
- get peerId() {
1991
- return self.peerId;
1992
- },
1993
- get audioEnabled() {
1994
- return self.audioEnabled;
1995
- },
1996
- get videoEnabled() {
1997
- return self.videoEnabled;
1998
- },
1999
- get screenShareEnabled() {
2000
- return self.screenShareEnabled;
2001
- },
2002
- get audioTrack() {
2003
- return self.audioTrack ?? null;
2004
- },
2005
- get videoTrack() {
2006
- return self.videoTrack ?? null;
2007
- },
2008
- get screenShareTracks() {
2009
- return {
2010
- ...self.screenShareTracks.audio ? { audio: self.screenShareTracks.audio } : {},
2011
- ...self.screenShareTracks.video ? { video: self.screenShareTracks.video } : {}
2012
- };
2013
- },
2014
- enableAudio: (customTrack) => self.enableAudio(customTrack),
2015
- enableVideo: (customTrack) => self.enableVideo(customTrack),
2016
- enableScreenShare: () => self.enableScreenShare(),
2017
- disableAudio: () => self.disableAudio(),
2018
- disableVideo: () => self.disableVideo(),
2019
- disableScreenShare: () => self.disableScreenShare(),
2020
- onAudioUpdate: (listener) => {
2021
- self.on("audioUpdate", listener);
2022
- return () => self.off("audioUpdate", listener);
2023
- },
2024
- onVideoUpdate: (listener) => {
2025
- self.on("videoUpdate", listener);
2026
- return () => self.off("videoUpdate", listener);
2027
- },
2028
- onScreenShareUpdate: (listener) => {
2029
- self.on("screenShareUpdate", listener);
2030
- return () => self.off("screenShareUpdate", listener);
2031
- },
2032
- onLeft: (listener) => {
2033
- self.on("roomLeft", listener);
2034
- return () => self.off("roomLeft", listener);
2035
- }
2036
- },
2037
- participants: {
2038
- joined: {
2039
- list: () => client.participants.joined.toArray().map(toParticipant),
2040
- onJoined: (listener) => {
2041
- const callback = (participant) => listener(toParticipant(participant));
2042
- client.participants.joined.on("participantJoined", callback);
2043
- return () => client.participants.joined.off("participantJoined", callback);
2044
- },
2045
- onLeft: (listener) => {
2046
- const callback = (participant) => listener(toParticipant(participant));
2047
- client.participants.joined.on("participantLeft", callback);
2048
- return () => client.participants.joined.off("participantLeft", callback);
2049
- }
2050
- }
2051
- }
2052
- };
2053
- }
2054
- function toParticipant(participant) {
2055
- return {
2056
- id: participant.id,
2057
- userId: participant.userId,
2058
- ...participant.customParticipantId === void 0 ? {} : { customParticipantId: participant.customParticipantId },
2059
- audioEnabled: participant.audioEnabled,
2060
- videoEnabled: participant.videoEnabled,
2061
- screenShareEnabled: participant.screenShareEnabled,
2062
- audioTrack: participant.audioTrack ?? null,
2063
- videoTrack: participant.videoTrack ?? null,
2064
- screenShareTracks: {
2065
- ...participant.screenShareTracks.audio ? { audio: participant.screenShareTracks.audio } : {},
2066
- ...participant.screenShareTracks.video ? { video: participant.screenShareTracks.video } : {}
2067
- },
2068
- onAudioUpdate: (listener) => {
2069
- const callback = () => listener();
2070
- participant.on("audioUpdate", callback);
2071
- return () => participant.off("audioUpdate", callback);
2072
- },
2073
- onVideoUpdate: (listener) => {
2074
- const callback = () => listener();
2075
- participant.on("videoUpdate", callback);
2076
- return () => participant.off("videoUpdate", callback);
2077
- },
2078
- onScreenShareUpdate: (listener) => {
2079
- const callback = () => listener();
2080
- participant.on("screenShareUpdate", callback);
2081
- return () => participant.off("screenShareUpdate", callback);
2082
- }
2083
- };
2084
- }
2085
- function isStaleGeneration(error) {
2086
- return error instanceof CloudflareRTKError && error.code === "stale_generation";
2087
- }
2088
-
2089
1499
  // src/media/capture-error.ts
2090
1500
  function describeMediaCaptureError(cause) {
2091
1501
  const name = typeof cause === "object" && cause !== null && "name" in cause ? cause.name : void 0;
@@ -2121,7 +1531,5 @@ export {
2121
1531
  publicationKey,
2122
1532
  waitFor,
2123
1533
  CloudflareSFUClient,
2124
- createCloudflareSFUHTTPTransport,
2125
- CloudflareRTKError,
2126
- CloudflareRTKClient
1534
+ createCloudflareSFUHTTPTransport
2127
1535
  };