@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.d.cts CHANGED
@@ -1375,6 +1375,38 @@ interface HoldSelectionRequest {
1375
1375
  interface BestAvailableResponse extends HoldResponse {
1376
1376
  labels: string[];
1377
1377
  }
1378
+ /** One unit's status as the realtime wire words it (`free`/`held`/`booked`/`blocked`/…). */
1379
+ interface PickerStatusChange {
1380
+ label: string;
1381
+ status: string;
1382
+ }
1383
+ /**
1384
+ * Where a transport-owned realtime client pushes reconstructed inventory.
1385
+ *
1386
+ * Structurally identical to the SDK's `RealtimeSink` on purpose: this file is
1387
+ * mirrored byte-for-byte into `@seatlayer/core`, which the SDK's `@seatlayer/js`
1388
+ * depends on — so it can never import BuyerRealtimeClient without inverting that
1389
+ * dependency. Structural typing lets the SDK hand its client this object with no
1390
+ * import in either direction.
1391
+ */
1392
+ interface PickerRealtimeSink {
1393
+ /** Apply a batch of label→status changes as ONE paint pass, not one per label. */
1394
+ applyStatuses(changes: PickerStatusChange[]): void;
1395
+ /** Re-pull authoritative state over HTTP (a frame that cannot be diffed). */
1396
+ resync(): void | Promise<void>;
1397
+ /** Section availability changed (hidden = stripped, closed = greyed). */
1398
+ onSections?(hidden: string[], closed: string[]): void;
1399
+ /** Scope-projected presence counters. Unused by the picker today. */
1400
+ onPresence?(counts: {
1401
+ shoppingSessions: number;
1402
+ activeHolds: number;
1403
+ }): void;
1404
+ }
1405
+ /** The live feed itself, owned by the transport. */
1406
+ interface PickerRealtimeConnection {
1407
+ start(): void;
1408
+ stop(): void;
1409
+ }
1378
1410
  /** Swappable public-surface transport (SDK PubApi or a dashboard `api.pub.*` adapter). */
1379
1411
  interface PickerTransport {
1380
1412
  chart(key: string): Promise<{
@@ -1413,6 +1445,17 @@ interface PickerTransport {
1413
1445
  * subscribe ticket via `Sec-WebSocket-Protocol`, realtime-protocol v1).
1414
1446
  * Absent or empty means today's plain connection. */
1415
1447
  socketProtocols?(key: string): string[];
1448
+ /**
1449
+ * Optional — the transport owns the live feed and hands back a client that
1450
+ * speaks the compact `seatlayer.v1` protocol (snapshot diffing, `sv.<n>`
1451
+ * resume, ping/pong liveness, jittered reconnect).
1452
+ *
1453
+ * When this returns a connection the controller does NOT open its own socket:
1454
+ * one socket client, one reconnect/backoff/resume implementation. Returning
1455
+ * null (or omitting the method) keeps the plain-WebSocket path below, which is
1456
+ * what a transport with no realtime client of its own still gets.
1457
+ */
1458
+ createRealtime?(key: string, sink: PickerRealtimeSink): PickerRealtimeConnection | null;
1416
1459
  }
1417
1460
  interface PickerCallbacks extends RendererCallbacks {
1418
1461
  /** Selection changed (manual clicks or a server best-available pick). */
@@ -1509,6 +1552,8 @@ declare class PickerController {
1509
1552
  private confirmedVariableTables;
1510
1553
  private groupedSelectionOverhead;
1511
1554
  private ws;
1555
+ /** Transport-owned v1 client; mutually exclusive with `ws`. */
1556
+ private realtime;
1512
1557
  private reconnectTimer;
1513
1558
  private attempt;
1514
1559
  private closed;
@@ -1813,7 +1858,28 @@ declare class PickerController {
1813
1858
  */
1814
1859
  private attachVisibilityListener;
1815
1860
  private detachVisibilityListener;
1861
+ /**
1862
+ * The sink a transport-owned v1 client pushes into.
1863
+ *
1864
+ * Deliberately byte-compatible with the inline socket handler below: the same
1865
+ * liveStatuses bookkeeping (which the hold-expiry verification reads), the
1866
+ * same one-call-per-status paint, the same free→taken flash rule that skips
1867
+ * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the
1868
+ * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same
1869
+ * callbacks in the same order whichever path is live.
1870
+ */
1871
+ private realtimeSink;
1872
+ /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */
1873
+ private applyStatusChanges;
1816
1874
  private connect;
1875
+ /**
1876
+ * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its
1877
+ * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a
1878
+ * deterministic `2**attempt` schedule brings every browser that lost the same
1879
+ * socket back in the same millisecond, and an on-sale crowd reconnecting in
1880
+ * lockstep turns one blip into a thundering herd. The ceiling still doubles,
1881
+ * so a sustained outage still backs off.
1882
+ */
1817
1883
  private scheduleReconnect;
1818
1884
  }
1819
1885
 
@@ -1968,4 +2034,4 @@ declare function formatMinor(minor: number, currency?: string): string;
1968
2034
  /** Bare symbol for input adornments ("€", "$", "₹"). */
1969
2035
  declare function currencySymbol(currency?: string): string;
1970
2036
 
1971
- export { AccessibilityType, type AvailabilityRule, BoothObject, CategoryTier, ChartDoc, ChartObject, DEFAULT_CURRENCY, type Dict, type ExpandChartOptions, ExpandedSeat, Floor, GAAreaObject, GAInventorySegment, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, ISeatmapRenderer, LabelStyle, type Locale, LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerGAArea, type PickerOptions, type PickerSeat, type PickerTransport, Point, RENDERED_QUALITY_REPORT_VERSION, RectTableSeatCounts, RectTableSide, type RenderedEvidenceState, RenderedFreeTextEvidence, type RenderedQualityFinding, type RenderedQualityFindingCode, type RenderedQualityReport, type RenderedQualitySample, RendererCallbacks, RendererOptions, RendererQualityEvidence, RendererViewMode, RowObject, type RowSeatSlot, SUPPORTED_LOCALES, SeatCommercialAttributes, type SeatHoverDetails, SeatOverride, SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, SectionObject, type SectionSummary, TIER_HEIGHT_M, TableObject, type TableSeatSlot, type TableSelectionDetails, UNGROUPED_ID, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencyExponent, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, expandTableSlots, floorObjects, floorsOf, formatDate, formatMinor, formatMoney, fromMinorUnits, gaAreasOf, gaInventorySegments, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, growJoinedGAInventory, hiddenObjectIds, inspectRenderedQualityEvidence, isGaUnitLabel, isSectionHidden, loadLocale, objectCenter, owningSectionForObject, pointInPolygon, pointInPolygonWithHoles, polygonLabelPoint, resolveLocale, rowInventoryCount, rowSeatPositions, sectionGeometry, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount, tableInventoryCount, tableSeatCountsBySide, validGAInventorySegments };
2037
+ export { AccessibilityType, type AvailabilityRule, BoothObject, CategoryTier, ChartDoc, ChartObject, DEFAULT_CURRENCY, type Dict, type ExpandChartOptions, ExpandedSeat, Floor, GAAreaObject, GAInventorySegment, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, ISeatmapRenderer, LabelStyle, type Locale, LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerGAArea, type PickerOptions, type PickerRealtimeConnection, type PickerRealtimeSink, type PickerSeat, type PickerStatusChange, type PickerTransport, Point, RENDERED_QUALITY_REPORT_VERSION, RectTableSeatCounts, RectTableSide, type RenderedEvidenceState, RenderedFreeTextEvidence, type RenderedQualityFinding, type RenderedQualityFindingCode, type RenderedQualityReport, type RenderedQualitySample, RendererCallbacks, RendererOptions, RendererQualityEvidence, RendererViewMode, RowObject, type RowSeatSlot, SUPPORTED_LOCALES, SeatCommercialAttributes, type SeatHoverDetails, SeatOverride, SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, SectionObject, type SectionSummary, TIER_HEIGHT_M, TableObject, type TableSeatSlot, type TableSelectionDetails, UNGROUPED_ID, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencyExponent, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, expandTableSlots, floorObjects, floorsOf, formatDate, formatMinor, formatMoney, fromMinorUnits, gaAreasOf, gaInventorySegments, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, growJoinedGAInventory, hiddenObjectIds, inspectRenderedQualityEvidence, isGaUnitLabel, isSectionHidden, loadLocale, objectCenter, owningSectionForObject, pointInPolygon, pointInPolygonWithHoles, polygonLabelPoint, resolveLocale, rowInventoryCount, rowSeatPositions, sectionGeometry, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount, tableInventoryCount, tableSeatCountsBySide, validGAInventorySegments };
package/dist/index.d.ts CHANGED
@@ -1375,6 +1375,38 @@ interface HoldSelectionRequest {
1375
1375
  interface BestAvailableResponse extends HoldResponse {
1376
1376
  labels: string[];
1377
1377
  }
1378
+ /** One unit's status as the realtime wire words it (`free`/`held`/`booked`/`blocked`/…). */
1379
+ interface PickerStatusChange {
1380
+ label: string;
1381
+ status: string;
1382
+ }
1383
+ /**
1384
+ * Where a transport-owned realtime client pushes reconstructed inventory.
1385
+ *
1386
+ * Structurally identical to the SDK's `RealtimeSink` on purpose: this file is
1387
+ * mirrored byte-for-byte into `@seatlayer/core`, which the SDK's `@seatlayer/js`
1388
+ * depends on — so it can never import BuyerRealtimeClient without inverting that
1389
+ * dependency. Structural typing lets the SDK hand its client this object with no
1390
+ * import in either direction.
1391
+ */
1392
+ interface PickerRealtimeSink {
1393
+ /** Apply a batch of label→status changes as ONE paint pass, not one per label. */
1394
+ applyStatuses(changes: PickerStatusChange[]): void;
1395
+ /** Re-pull authoritative state over HTTP (a frame that cannot be diffed). */
1396
+ resync(): void | Promise<void>;
1397
+ /** Section availability changed (hidden = stripped, closed = greyed). */
1398
+ onSections?(hidden: string[], closed: string[]): void;
1399
+ /** Scope-projected presence counters. Unused by the picker today. */
1400
+ onPresence?(counts: {
1401
+ shoppingSessions: number;
1402
+ activeHolds: number;
1403
+ }): void;
1404
+ }
1405
+ /** The live feed itself, owned by the transport. */
1406
+ interface PickerRealtimeConnection {
1407
+ start(): void;
1408
+ stop(): void;
1409
+ }
1378
1410
  /** Swappable public-surface transport (SDK PubApi or a dashboard `api.pub.*` adapter). */
1379
1411
  interface PickerTransport {
1380
1412
  chart(key: string): Promise<{
@@ -1413,6 +1445,17 @@ interface PickerTransport {
1413
1445
  * subscribe ticket via `Sec-WebSocket-Protocol`, realtime-protocol v1).
1414
1446
  * Absent or empty means today's plain connection. */
1415
1447
  socketProtocols?(key: string): string[];
1448
+ /**
1449
+ * Optional — the transport owns the live feed and hands back a client that
1450
+ * speaks the compact `seatlayer.v1` protocol (snapshot diffing, `sv.<n>`
1451
+ * resume, ping/pong liveness, jittered reconnect).
1452
+ *
1453
+ * When this returns a connection the controller does NOT open its own socket:
1454
+ * one socket client, one reconnect/backoff/resume implementation. Returning
1455
+ * null (or omitting the method) keeps the plain-WebSocket path below, which is
1456
+ * what a transport with no realtime client of its own still gets.
1457
+ */
1458
+ createRealtime?(key: string, sink: PickerRealtimeSink): PickerRealtimeConnection | null;
1416
1459
  }
1417
1460
  interface PickerCallbacks extends RendererCallbacks {
1418
1461
  /** Selection changed (manual clicks or a server best-available pick). */
@@ -1509,6 +1552,8 @@ declare class PickerController {
1509
1552
  private confirmedVariableTables;
1510
1553
  private groupedSelectionOverhead;
1511
1554
  private ws;
1555
+ /** Transport-owned v1 client; mutually exclusive with `ws`. */
1556
+ private realtime;
1512
1557
  private reconnectTimer;
1513
1558
  private attempt;
1514
1559
  private closed;
@@ -1813,7 +1858,28 @@ declare class PickerController {
1813
1858
  */
1814
1859
  private attachVisibilityListener;
1815
1860
  private detachVisibilityListener;
1861
+ /**
1862
+ * The sink a transport-owned v1 client pushes into.
1863
+ *
1864
+ * Deliberately byte-compatible with the inline socket handler below: the same
1865
+ * liveStatuses bookkeeping (which the hold-expiry verification reads), the
1866
+ * same one-call-per-status paint, the same free→taken flash rule that skips
1867
+ * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the
1868
+ * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same
1869
+ * callbacks in the same order whichever path is live.
1870
+ */
1871
+ private realtimeSink;
1872
+ /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */
1873
+ private applyStatusChanges;
1816
1874
  private connect;
1875
+ /**
1876
+ * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its
1877
+ * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a
1878
+ * deterministic `2**attempt` schedule brings every browser that lost the same
1879
+ * socket back in the same millisecond, and an on-sale crowd reconnecting in
1880
+ * lockstep turns one blip into a thundering herd. The ceiling still doubles,
1881
+ * so a sustained outage still backs off.
1882
+ */
1817
1883
  private scheduleReconnect;
1818
1884
  }
1819
1885
 
@@ -1968,4 +2034,4 @@ declare function formatMinor(minor: number, currency?: string): string;
1968
2034
  /** Bare symbol for input adornments ("€", "$", "₹"). */
1969
2035
  declare function currencySymbol(currency?: string): string;
1970
2036
 
1971
- export { AccessibilityType, type AvailabilityRule, BoothObject, CategoryTier, ChartDoc, ChartObject, DEFAULT_CURRENCY, type Dict, type ExpandChartOptions, ExpandedSeat, Floor, GAAreaObject, GAInventorySegment, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, ISeatmapRenderer, LabelStyle, type Locale, LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerGAArea, type PickerOptions, type PickerSeat, type PickerTransport, Point, RENDERED_QUALITY_REPORT_VERSION, RectTableSeatCounts, RectTableSide, type RenderedEvidenceState, RenderedFreeTextEvidence, type RenderedQualityFinding, type RenderedQualityFindingCode, type RenderedQualityReport, type RenderedQualitySample, RendererCallbacks, RendererOptions, RendererQualityEvidence, RendererViewMode, RowObject, type RowSeatSlot, SUPPORTED_LOCALES, SeatCommercialAttributes, type SeatHoverDetails, SeatOverride, SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, SectionObject, type SectionSummary, TIER_HEIGHT_M, TableObject, type TableSeatSlot, type TableSelectionDetails, UNGROUPED_ID, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencyExponent, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, expandTableSlots, floorObjects, floorsOf, formatDate, formatMinor, formatMoney, fromMinorUnits, gaAreasOf, gaInventorySegments, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, growJoinedGAInventory, hiddenObjectIds, inspectRenderedQualityEvidence, isGaUnitLabel, isSectionHidden, loadLocale, objectCenter, owningSectionForObject, pointInPolygon, pointInPolygonWithHoles, polygonLabelPoint, resolveLocale, rowInventoryCount, rowSeatPositions, sectionGeometry, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount, tableInventoryCount, tableSeatCountsBySide, validGAInventorySegments };
2037
+ export { AccessibilityType, type AvailabilityRule, BoothObject, CategoryTier, ChartDoc, ChartObject, DEFAULT_CURRENCY, type Dict, type ExpandChartOptions, ExpandedSeat, Floor, GAAreaObject, GAInventorySegment, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, ISeatmapRenderer, LabelStyle, type Locale, LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerGAArea, type PickerOptions, type PickerRealtimeConnection, type PickerRealtimeSink, type PickerSeat, type PickerStatusChange, type PickerTransport, Point, RENDERED_QUALITY_REPORT_VERSION, RectTableSeatCounts, RectTableSide, type RenderedEvidenceState, RenderedFreeTextEvidence, type RenderedQualityFinding, type RenderedQualityFindingCode, type RenderedQualityReport, type RenderedQualitySample, RendererCallbacks, RendererOptions, RendererQualityEvidence, RendererViewMode, RowObject, type RowSeatSlot, SUPPORTED_LOCALES, SeatCommercialAttributes, type SeatHoverDetails, SeatOverride, SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, SectionObject, type SectionSummary, TIER_HEIGHT_M, TableObject, type TableSeatSlot, type TableSelectionDetails, UNGROUPED_ID, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencyExponent, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, expandTableSlots, floorObjects, floorsOf, formatDate, formatMinor, formatMoney, fromMinorUnits, gaAreasOf, gaInventorySegments, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, growJoinedGAInventory, hiddenObjectIds, inspectRenderedQualityEvidence, isGaUnitLabel, isSectionHidden, loadLocale, objectCenter, owningSectionForObject, pointInPolygon, pointInPolygonWithHoles, polygonLabelPoint, resolveLocale, rowInventoryCount, rowSeatPositions, sectionGeometry, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount, tableInventoryCount, tableSeatCountsBySide, validGAInventorySegments };
package/dist/index.js CHANGED
@@ -6611,6 +6611,8 @@ var PickerController = class {
6611
6611
  this.groupedSelectionOverhead = 0;
6612
6612
  // realtime socket
6613
6613
  this.ws = null;
6614
+ /** Transport-owned v1 client; mutually exclusive with `ws`. */
6615
+ this.realtime = null;
6614
6616
  this.reconnectTimer = null;
6615
6617
  this.attempt = 0;
6616
6618
  this.closed = false;
@@ -7660,6 +7662,13 @@ var PickerController = class {
7660
7662
  clearTimeout(this.expiryTimer);
7661
7663
  this.expiryTimer = null;
7662
7664
  }
7665
+ if (this.realtime) {
7666
+ try {
7667
+ this.realtime.stop();
7668
+ } catch {
7669
+ }
7670
+ this.realtime = null;
7671
+ }
7663
7672
  if (this.ws) {
7664
7673
  try {
7665
7674
  this.ws.close();
@@ -7948,10 +7957,66 @@ var PickerController = class {
7948
7957
  }
7949
7958
  this.onVisibilityChange = null;
7950
7959
  }
7960
+ /**
7961
+ * The sink a transport-owned v1 client pushes into.
7962
+ *
7963
+ * Deliberately byte-compatible with the inline socket handler below: the same
7964
+ * liveStatuses bookkeeping (which the hold-expiry verification reads), the
7965
+ * same one-call-per-status paint, the same free→taken flash rule that skips
7966
+ * the buyer's OWN just-held seats, the same keepLiveWhileHidden forceDraw, the
7967
+ * same clearBookedHoldIfSettled + onStatusChange ordering. Hosts see the same
7968
+ * callbacks in the same order whichever path is live.
7969
+ */
7970
+ realtimeSink() {
7971
+ return {
7972
+ applyStatuses: (changes) => this.applyStatusChanges(changes),
7973
+ resync: () => this.resnapshot(),
7974
+ onSections: (hidden, closed) => {
7975
+ const rebuilt = this.syncHidden(hidden);
7976
+ const restyled = this.syncClosed(closed);
7977
+ if (rebuilt) void this.resnapshot();
7978
+ if (rebuilt || restyled) this.opts.onStatusChange?.();
7979
+ }
7980
+ };
7981
+ }
7982
+ /** Paint one delta batch. Shared by the v1 sink and the plain-socket handler. */
7983
+ applyStatusChanges(changes) {
7984
+ const r = this.renderer;
7985
+ if (!r) return;
7986
+ for (const ch of changes) {
7987
+ this.liveStatuses.set(ch.label, ch.status);
7988
+ const ids = this.idsForLabel(ch.label);
7989
+ if (!ids.length) continue;
7990
+ const next = mapStatus(ch.status);
7991
+ if (this.opts.flashOnLiveChange && next !== "free" && ids.some((id) => r.getStatus(id) === "free") && !this.hold_?.labels.includes(ch.label)) {
7992
+ ids.forEach((id) => r.flashSeat(id, next === "held" ? "#f4b740" : "#f43f5e"));
7993
+ }
7994
+ r.setStatus(ids, next);
7995
+ }
7996
+ if (this.opts.keepLiveWhileHidden && typeof document !== "undefined" && document.visibilityState === "hidden") {
7997
+ r.forceDraw();
7998
+ }
7999
+ this.clearBookedHoldIfSettled();
8000
+ this.opts.onStatusChange?.();
8001
+ }
7951
8002
  connect() {
7952
8003
  if (this.closed) return;
7953
8004
  const url = this.api.socketUrl(this.key);
7954
8005
  if (!url) return;
8006
+ if (!this.realtime && this.api.createRealtime) {
8007
+ let connection = null;
8008
+ try {
8009
+ connection = this.api.createRealtime(this.key, this.realtimeSink());
8010
+ } catch {
8011
+ connection = null;
8012
+ }
8013
+ if (connection) {
8014
+ this.realtime = connection;
8015
+ connection.start();
8016
+ return;
8017
+ }
8018
+ }
8019
+ if (this.realtime) return;
7955
8020
  let ws;
7956
8021
  try {
7957
8022
  const protocols = this.api.socketProtocols?.(this.key);
@@ -7986,21 +8051,7 @@ var PickerController = class {
7986
8051
  if (m.seats && typeof m.seats === "object") {
7987
8052
  this.applySeatsMap(m.seats);
7988
8053
  } else if (Array.isArray(m.changes)) {
7989
- for (const ch of m.changes) {
7990
- this.liveStatuses.set(ch.label, ch.status);
7991
- const ids = this.idsForLabel(ch.label);
7992
- if (!ids.length) continue;
7993
- const next = mapStatus(ch.status);
7994
- if (this.opts.flashOnLiveChange && next !== "free" && ids.some((id) => r.getStatus(id) === "free") && !this.hold_?.labels.includes(ch.label)) {
7995
- ids.forEach((id) => r.flashSeat(id, next === "held" ? "#f4b740" : "#f43f5e"));
7996
- }
7997
- r.setStatus(ids, next);
7998
- }
7999
- if (this.opts.keepLiveWhileHidden && typeof document !== "undefined" && document.visibilityState === "hidden") {
8000
- r.forceDraw();
8001
- }
8002
- this.clearBookedHoldIfSettled();
8003
- this.opts.onStatusChange?.();
8054
+ this.applyStatusChanges(m.changes);
8004
8055
  }
8005
8056
  };
8006
8057
  ws.onclose = () => {
@@ -8014,10 +8065,18 @@ var PickerController = class {
8014
8065
  }
8015
8066
  };
8016
8067
  }
8068
+ /**
8069
+ * Backoff for the PLAIN-socket fallback (a transport with no v1 client of its
8070
+ * own). Full jitter, for the same reason BuyerRealtimeClient uses it: a
8071
+ * deterministic `2**attempt` schedule brings every browser that lost the same
8072
+ * socket back in the same millisecond, and an on-sale crowd reconnecting in
8073
+ * lockstep turns one blip into a thundering herd. The ceiling still doubles,
8074
+ * so a sustained outage still backs off.
8075
+ */
8017
8076
  scheduleReconnect() {
8018
8077
  if (this.closed || this.reconnectTimer) return;
8019
8078
  const attempt = Math.min(this.attempt++, 5);
8020
- const delay = Math.min(1e3 * 2 ** attempt, MAX_BACKOFF_MS);
8079
+ const delay = Math.random() * Math.min(1e3 * 2 ** attempt, MAX_BACKOFF_MS);
8021
8080
  this.reconnectTimer = setTimeout(() => {
8022
8081
  this.reconnectTimer = null;
8023
8082
  this.connect();