@seatlayer/core 0.28.2 → 0.28.4

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
@@ -2749,7 +2749,7 @@ interface PickerTransport {
2749
2749
  closed?: string[];
2750
2750
  }>;
2751
2751
  hold(key: string, selections: HoldSelectionRequest[], ttlMs?: number, replaceHoldId?: string): Promise<HoldResponse>;
2752
- bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string): Promise<BestAvailableResponse>;
2752
+ bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string, ttlMs?: number): Promise<BestAvailableResponse>;
2753
2753
  release(key: string, labels: string[], holdId: string): Promise<unknown>;
2754
2754
  /** Optional capability-style lookup used to restore an active browser hold. */
2755
2755
  resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;
@@ -2923,8 +2923,12 @@ declare class PickerController {
2923
2923
  select(ids: string[]): PickerSeat[];
2924
2924
  /** Confirm/update the guest quantity for a selected variable table. */
2925
2925
  setTableQuantity(label: string, quantity: number): boolean;
2926
- /** Atomically replace an active variable-table hold with a new guest count. */
2927
- replaceTableQuantity(label: string, quantity: number): Promise<HoldInfo | null>;
2926
+ /**
2927
+ * Atomically replace an active variable-table hold with a new guest count.
2928
+ * `ttlMs` keeps the host's checkout window across the replacement — without it
2929
+ * a guest-count change silently re-based the countdown on the server default.
2930
+ */
2931
+ replaceTableQuantity(label: string, quantity: number, ttlMs?: number): Promise<HoldInfo | null>;
2928
2932
  private rendererSelectionCap;
2929
2933
  private selectionGuestCount;
2930
2934
  private handleRendererSelect;
@@ -2987,10 +2991,15 @@ declare class PickerController {
2987
2991
  * failure. With `preferPremium`, first tries to hold the best PREMIUM block
2988
2992
  * locally; when none matches the requested quantity it falls back to the
2989
2993
  * normal server pick (the widget surfaces a subtle note on that fallback).
2994
+ *
2995
+ * `ttlMs` is the host's checkout window and MUST reach both branches: a hold
2996
+ * born here is the same buyer commitment as one made by clicking seats, so
2997
+ * omitting it silently handed the buyer the server default instead.
2990
2998
  */
2991
2999
  bestAvailable(qty: number, categoryKey?: string, opts?: {
2992
3000
  preferPremium?: boolean;
2993
3001
  zoneId?: string;
3002
+ ttlMs?: number;
2994
3003
  }): Promise<HoldInfo | null>;
2995
3004
  /**
2996
3005
  * Complete a booking. Requires a transport that supports book() (the SDK
@@ -2999,8 +3008,10 @@ declare class PickerController {
2999
3008
  * cart can hold best-available seats that aren't in the renderer selection);
3000
3009
  * defaults to the renderer selection. Reuses an existing exact-match hold, else
3001
3010
  * holds first. Returns the labels booked, or null on failure (conflicts painted).
3011
+ * `ttlMs` only matters on the hold-first path: if the book call then fails, the
3012
+ * seats sit held for the host's window rather than the longer server default.
3002
3013
  */
3003
- book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null>;
3014
+ book(bookingRef: string, labelsArg?: string[], ttlMs?: number): Promise<string[] | null>;
3004
3015
  /** Release the whole open hold (if any), repaint those seats free. */
3005
3016
  release(): Promise<boolean>;
3006
3017
  /**
package/dist/index.d.ts CHANGED
@@ -2749,7 +2749,7 @@ interface PickerTransport {
2749
2749
  closed?: string[];
2750
2750
  }>;
2751
2751
  hold(key: string, selections: HoldSelectionRequest[], ttlMs?: number, replaceHoldId?: string): Promise<HoldResponse>;
2752
- bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string): Promise<BestAvailableResponse>;
2752
+ bestAvailable(key: string, qty: number, categoryKey?: string, zoneId?: string, ttlMs?: number): Promise<BestAvailableResponse>;
2753
2753
  release(key: string, labels: string[], holdId: string): Promise<unknown>;
2754
2754
  /** Optional capability-style lookup used to restore an active browser hold. */
2755
2755
  resume?(key: string, holdId: string): Promise<ResumeHoldResponse>;
@@ -2923,8 +2923,12 @@ declare class PickerController {
2923
2923
  select(ids: string[]): PickerSeat[];
2924
2924
  /** Confirm/update the guest quantity for a selected variable table. */
2925
2925
  setTableQuantity(label: string, quantity: number): boolean;
2926
- /** Atomically replace an active variable-table hold with a new guest count. */
2927
- replaceTableQuantity(label: string, quantity: number): Promise<HoldInfo | null>;
2926
+ /**
2927
+ * Atomically replace an active variable-table hold with a new guest count.
2928
+ * `ttlMs` keeps the host's checkout window across the replacement — without it
2929
+ * a guest-count change silently re-based the countdown on the server default.
2930
+ */
2931
+ replaceTableQuantity(label: string, quantity: number, ttlMs?: number): Promise<HoldInfo | null>;
2928
2932
  private rendererSelectionCap;
2929
2933
  private selectionGuestCount;
2930
2934
  private handleRendererSelect;
@@ -2987,10 +2991,15 @@ declare class PickerController {
2987
2991
  * failure. With `preferPremium`, first tries to hold the best PREMIUM block
2988
2992
  * locally; when none matches the requested quantity it falls back to the
2989
2993
  * normal server pick (the widget surfaces a subtle note on that fallback).
2994
+ *
2995
+ * `ttlMs` is the host's checkout window and MUST reach both branches: a hold
2996
+ * born here is the same buyer commitment as one made by clicking seats, so
2997
+ * omitting it silently handed the buyer the server default instead.
2990
2998
  */
2991
2999
  bestAvailable(qty: number, categoryKey?: string, opts?: {
2992
3000
  preferPremium?: boolean;
2993
3001
  zoneId?: string;
3002
+ ttlMs?: number;
2994
3003
  }): Promise<HoldInfo | null>;
2995
3004
  /**
2996
3005
  * Complete a booking. Requires a transport that supports book() (the SDK
@@ -2999,8 +3008,10 @@ declare class PickerController {
2999
3008
  * cart can hold best-available seats that aren't in the renderer selection);
3000
3009
  * defaults to the renderer selection. Reuses an existing exact-match hold, else
3001
3010
  * holds first. Returns the labels booked, or null on failure (conflicts painted).
3011
+ * `ttlMs` only matters on the hold-first path: if the book call then fails, the
3012
+ * seats sit held for the host's window rather than the longer server default.
3002
3013
  */
3003
- book(bookingRef: string, labelsArg?: string[]): Promise<string[] | null>;
3014
+ book(bookingRef: string, labelsArg?: string[], ttlMs?: number): Promise<string[] | null>;
3004
3015
  /** Release the whole open hold (if any), repaint those seats free. */
3005
3016
  release(): Promise<boolean>;
3006
3017
  /**
package/dist/index.js CHANGED
@@ -1090,9 +1090,10 @@ function compositeHexOver(foreground, background, opacity) {
1090
1090
  const channels = front.map((value, index) => Math.round(value * alpha + back[index] * (1 - alpha)));
1091
1091
  return `#${channels.map((value) => value.toString(16).padStart(2, "0")).join("")}`;
1092
1092
  }
1093
- function stateAwareBookableLabelInk(fill, preferred) {
1093
+ var AUTHORED_LABEL_MIN_CONTRAST = 3;
1094
+ function stateAwareBookableLabelInk(fill, preferred, minContrast = SMALL_TEXT_CONTRAST) {
1094
1095
  const preferredContrast = renderedTextContrast(preferred, fill);
1095
- if (preferredContrast != null && preferredContrast >= SMALL_TEXT_CONTRAST) return preferred;
1096
+ if (preferredContrast != null && preferredContrast >= minContrast) return preferred;
1096
1097
  const darkContrast = renderedTextContrast(DARK_BOOKABLE_LABEL_INK, fill) ?? 0;
1097
1098
  const lightContrast = renderedTextContrast(LIGHT_BOOKABLE_LABEL_INK, fill) ?? 0;
1098
1099
  if (darkContrast === 0 && lightContrast === 0) return preferred;
@@ -4507,7 +4508,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
4507
4508
  * authored per-seat colour through the same auto-contrast rule as sections. */
4508
4509
  seatLabelInk(seat, shape) {
4509
4510
  const fill = shape.fill();
4510
- return stateAwareBookableLabelInk(typeof fill === "string" ? fill : "", this.seatPreferredLabelInk(seat));
4511
+ return stateAwareBookableLabelInk(typeof fill === "string" ? fill : "", this.seatPreferredLabelInk(seat), AUTHORED_LABEL_MIN_CONTRAST);
4511
4512
  }
4512
4513
  /** Apply fill/stroke/opacity for a seat's current status + selection. */
4513
4514
  paintSeat(c, id) {
@@ -6675,7 +6676,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
6675
6676
  const labelStyle = presentation?.labelStyle;
6676
6677
  const ink = stateAwareBookableLabelInk(
6677
6678
  background,
6678
- labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? "#e6e9f0"
6679
+ labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? "#e6e9f0",
6680
+ AUTHORED_LABEL_MIN_CONTRAST
6679
6681
  );
6680
6682
  const fontSize = labelStyle?.size ?? 12;
6681
6683
  const rotation = presentation?.rotation ?? 0;
@@ -7404,8 +7406,12 @@ var PickerController = class {
7404
7406
  this.emitSelectionChange();
7405
7407
  return true;
7406
7408
  }
7407
- /** Atomically replace an active variable-table hold with a new guest count. */
7408
- async replaceTableQuantity(label, quantity) {
7409
+ /**
7410
+ * Atomically replace an active variable-table hold with a new guest count.
7411
+ * `ttlMs` keeps the host's checkout window across the replacement — without it
7412
+ * a guest-count change silently re-based the countdown on the server default.
7413
+ */
7414
+ async replaceTableQuantity(label, quantity, ttlMs) {
7409
7415
  const table = this.groupedTablesByLabel.get(label);
7410
7416
  const hold = this.hold_;
7411
7417
  if (!table || table.mode !== "variable" || !hold?.labels.includes(label)) return null;
@@ -7422,7 +7428,7 @@ var PickerController = class {
7422
7428
  quantity: item.label === label ? q : item.quantity
7423
7429
  }));
7424
7430
  if (!selections.some((item) => item.label === label)) return null;
7425
- const result = await this.api.hold(this.key, selections, void 0, hold.holdId);
7431
+ const result = await this.api.hold(this.key, selections, ttlMs, hold.holdId);
7426
7432
  this.tableQuantities.set(label, q);
7427
7433
  this.setHold({
7428
7434
  holdId: result.holdId,
@@ -7706,6 +7712,10 @@ var PickerController = class {
7706
7712
  * failure. With `preferPremium`, first tries to hold the best PREMIUM block
7707
7713
  * locally; when none matches the requested quantity it falls back to the
7708
7714
  * normal server pick (the widget surfaces a subtle note on that fallback).
7715
+ *
7716
+ * `ttlMs` is the host's checkout window and MUST reach both branches: a hold
7717
+ * born here is the same buyer commitment as one made by clicking seats, so
7718
+ * omitting it silently handed the buyer the server default instead.
7709
7719
  */
7710
7720
  async bestAvailable(qty, categoryKey, opts = {}) {
7711
7721
  const r = this.renderer;
@@ -7720,7 +7730,7 @@ var PickerController = class {
7720
7730
  const resolved = seat ? this.toSeat(seat) : null;
7721
7731
  return { label, ...resolved?.tierId ? { tierId: resolved.tierId } : {} };
7722
7732
  });
7723
- const result = await this.api.hold(this.key, selection);
7733
+ const result = await this.api.hold(this.key, selection, opts.ttlMs);
7724
7734
  r.clearSelection();
7725
7735
  const ids = this.idsForLabels(block);
7726
7736
  if (ids.length) r.setStatus(ids, "held");
@@ -7739,7 +7749,7 @@ var PickerController = class {
7739
7749
  }
7740
7750
  if (this.hold_ && !await this.release()) return null;
7741
7751
  try {
7742
- const result = await this.api.bestAvailable(this.key, qty, categoryKey, opts.zoneId);
7752
+ const result = await this.api.bestAvailable(this.key, qty, categoryKey, opts.zoneId, opts.ttlMs);
7743
7753
  r.clearSelection();
7744
7754
  const ids = this.idsForLabels(result.labels);
7745
7755
  if (ids.length) r.setStatus(ids, "held");
@@ -7760,8 +7770,10 @@ var PickerController = class {
7760
7770
  * cart can hold best-available seats that aren't in the renderer selection);
7761
7771
  * defaults to the renderer selection. Reuses an existing exact-match hold, else
7762
7772
  * holds first. Returns the labels booked, or null on failure (conflicts painted).
7773
+ * `ttlMs` only matters on the hold-first path: if the book call then fails, the
7774
+ * seats sit held for the host's window rather than the longer server default.
7763
7775
  */
7764
- async book(bookingRef, labelsArg) {
7776
+ async book(bookingRef, labelsArg, ttlMs) {
7765
7777
  const r = this.renderer;
7766
7778
  if (!r) return null;
7767
7779
  if (!this.api.book) throw new Error("picker: transport has no book() \u2014 hold-only mode");
@@ -7784,7 +7796,7 @@ var PickerController = class {
7784
7796
  ...this.tableQuantityRequest(resolved)
7785
7797
  };
7786
7798
  }),
7787
- void 0,
7799
+ ttlMs,
7788
7800
  replaceHoldId
7789
7801
  );
7790
7802
  holdId = h.holdId;