@seatlayer/core 0.38.0 → 0.40.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/index.cjs CHANGED
@@ -8202,6 +8202,8 @@ var PickerController = class {
8202
8202
  this.groupedSelectionOverhead = 0;
8203
8203
  // realtime socket
8204
8204
  this.ws = null;
8205
+ /** Transport-owned v1 client; mutually exclusive with `ws`. */
8206
+ this.realtime = null;
8205
8207
  this.reconnectTimer = null;
8206
8208
  this.attempt = 0;
8207
8209
  this.closed = false;
@@ -9251,6 +9253,13 @@ var PickerController = class {
9251
9253
  clearTimeout(this.expiryTimer);
9252
9254
  this.expiryTimer = null;
9253
9255
  }
9256
+ if (this.realtime) {
9257
+ try {
9258
+ this.realtime.stop();
9259
+ } catch {
9260
+ }
9261
+ this.realtime = null;
9262
+ }
9254
9263
  if (this.ws) {
9255
9264
  try {
9256
9265
  this.ws.close();
@@ -9539,10 +9548,66 @@ var PickerController = class {
9539
9548
  }
9540
9549
  this.onVisibilityChange = null;
9541
9550
  }
9551
+ /**
9552
+ * The sink a transport-owned v1 client pushes into.
9553
+ *
9554
+ * Deliberately byte-compatible with the inline socket handler below: the same
9555
+ * liveStatuses bookkeeping (which the hold-expiry verification reads), the
9556
+ * same one-call-per-status paint, the same free→taken flash rule that skips
9557
+ * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the
9558
+ * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same
9559
+ * callbacks in the same order whichever path is live.
9560
+ */
9561
+ realtimeSink() {
9562
+ return {
9563
+ applyStatuses: (changes) => this.applyStatusChanges(changes),
9564
+ resync: () => this.resnapshot(),
9565
+ onSections: (hidden, closed) => {
9566
+ const rebuilt = this.syncHidden(hidden);
9567
+ const restyled = this.syncClosed(closed);
9568
+ if (rebuilt) void this.resnapshot();
9569
+ if (rebuilt || restyled) this.opts.onStatusChange?.();
9570
+ }
9571
+ };
9572
+ }
9573
+ /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */
9574
+ applyStatusChanges(changes) {
9575
+ const r = this.renderer;
9576
+ if (!r) return;
9577
+ for (const ch of changes) {
9578
+ this.liveStatuses.set(ch.label, ch.status);
9579
+ const ids = this.idsForLabel(ch.label);
9580
+ if (!ids.length) continue;
9581
+ const next = mapStatus(ch.status);
9582
+ if (this.opts.flashOnLiveChange && next !== "free" && ids.some((id) => r.getStatus(id) === "free") && !this.hold_?.labels.includes(ch.label)) {
9583
+ ids.forEach((id) => r.flashSeat(id, next === "held" ? "#f4b740" : "#f43f5e"));
9584
+ }
9585
+ r.setStatus(ids, next);
9586
+ }
9587
+ if (this.opts.keepLiveWhileHidden && typeof document !== "undefined" && document.visibilityState === "hidden") {
9588
+ r.forceDraw();
9589
+ }
9590
+ this.clearBookedHoldIfSettled();
9591
+ this.opts.onStatusChange?.();
9592
+ }
9542
9593
  connect() {
9543
9594
  if (this.closed) return;
9544
9595
  const url = this.api.socketUrl(this.key);
9545
9596
  if (!url) return;
9597
+ if (!this.realtime && this.api.createRealtime) {
9598
+ let connection = null;
9599
+ try {
9600
+ connection = this.api.createRealtime(this.key, this.realtimeSink());
9601
+ } catch {
9602
+ connection = null;
9603
+ }
9604
+ if (connection) {
9605
+ this.realtime = connection;
9606
+ connection.start();
9607
+ return;
9608
+ }
9609
+ }
9610
+ if (this.realtime) return;
9546
9611
  let ws;
9547
9612
  try {
9548
9613
  const protocols = this.api.socketProtocols?.(this.key);
@@ -9577,21 +9642,7 @@ var PickerController = class {
9577
9642
  if (m.seats && typeof m.seats === "object") {
9578
9643
  this.applySeatsMap(m.seats);
9579
9644
  } else if (Array.isArray(m.changes)) {
9580
- for (const ch of m.changes) {
9581
- this.liveStatuses.set(ch.label, ch.status);
9582
- const ids = this.idsForLabel(ch.label);
9583
- if (!ids.length) continue;
9584
- const next = mapStatus(ch.status);
9585
- if (this.opts.flashOnLiveChange && next !== "free" && ids.some((id) => r.getStatus(id) === "free") && !this.hold_?.labels.includes(ch.label)) {
9586
- ids.forEach((id) => r.flashSeat(id, next === "held" ? "#f4b740" : "#f43f5e"));
9587
- }
9588
- r.setStatus(ids, next);
9589
- }
9590
- if (this.opts.keepLiveWhileHidden && typeof document !== "undefined" && document.visibilityState === "hidden") {
9591
- r.forceDraw();
9592
- }
9593
- this.clearBookedHoldIfSettled();
9594
- this.opts.onStatusChange?.();
9645
+ this.applyStatusChanges(m.changes);
9595
9646
  }
9596
9647
  };
9597
9648
  ws.onclose = () => {
@@ -9605,10 +9656,18 @@ var PickerController = class {
9605
9656
  }
9606
9657
  };
9607
9658
  }
9659
+ /**
9660
+ * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its
9661
+ * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a
9662
+ * deterministic `2**attempt` schedule brings every browser that lost the same
9663
+ * socket back in the same millisecond, and an on-sale crowd reconnecting in
9664
+ * lockstep turns one blip into a thundering herd. The ceiling still doubles,
9665
+ * so a sustained outage still backs off.
9666
+ */
9608
9667
  scheduleReconnect() {
9609
9668
  if (this.closed || this.reconnectTimer) return;
9610
9669
  const attempt = Math.min(this.attempt++, 5);
9611
- const delay = Math.min(1e3 * 2 ** attempt, MAX_BACKOFF_MS);
9670
+ const delay = Math.random() * Math.min(1e3 * 2 ** attempt, MAX_BACKOFF_MS);
9612
9671
  this.reconnectTimer = setTimeout(() => {
9613
9672
  this.reconnectTimer = null;
9614
9673
  this.connect();