@seatlayer/core 0.7.3 → 0.9.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
@@ -297,6 +297,8 @@ __export(index_exports, {
297
297
  gaAreasOf: () => gaAreasOf,
298
298
  gaUnitLabel: () => gaUnitLabel,
299
299
  gaUnitLabels: () => gaUnitLabels,
300
+ generateSeatPanorama: () => generateSeatPanorama,
301
+ generateSeatThumb: () => generateSeatThumb,
300
302
  getLocale: () => getLocale,
301
303
  hiddenObjectIds: () => hiddenObjectIds,
302
304
  isGaUnitLabel: () => isGaUnitLabel,
@@ -3133,6 +3135,26 @@ var PickerController = class {
3133
3135
  throw err;
3134
3136
  }
3135
3137
  }
3138
+ /**
3139
+ * P4 "need more time?": extend the OPEN hold's server-side expiry and re-arm
3140
+ * the client expiry timer to match (via setHold), so the controller doesn't
3141
+ * fire a false expiry and start polling. Returns the new hold, or null if
3142
+ * there's no open hold or the transport can't extend / the server refused
3143
+ * (hold gone, expired, or at its renewal cap). Never throws for the refusal
3144
+ * case — the caller decides the copy.
3145
+ */
3146
+ async extendHold(ttlMs) {
3147
+ const current = this.hold_;
3148
+ if (!current || !this.api.extend) return null;
3149
+ try {
3150
+ const result = await this.api.extend(this.key, current.holdId, ttlMs);
3151
+ if (this.hold_?.holdId !== current.holdId) return this.hold_;
3152
+ this.setHold({ holdId: current.holdId, labels: current.labels, expiresAt: result.expiresAt, items: current.items });
3153
+ return this.hold_;
3154
+ } catch {
3155
+ return null;
3156
+ }
3157
+ }
3136
3158
  /** Public GA inventory derived from the live synthetic-unit status stream. */
3137
3159
  /**
3138
3160
  * Live seats-left per category key (status 'free' right now). Recompute on
@@ -3718,6 +3740,202 @@ var PickerController = class {
3718
3740
  }
3719
3741
  };
3720
3742
 
3743
+ // src/view/generatePanorama.ts
3744
+ var W = 2048;
3745
+ var H = 1024;
3746
+ var UNIT = 0.55 / 24;
3747
+ var yawToX = (yawDeg) => (yawDeg + 180) / 360 * W;
3748
+ var pitchToY = (pitchDeg) => (90 - pitchDeg) / 180 * H;
3749
+ function generateSeatPanorama(seat, focalPoint, neighborSeats) {
3750
+ const canvas = document.createElement("canvas");
3751
+ canvas.width = W;
3752
+ canvas.height = H;
3753
+ const ctx = canvas.getContext("2d");
3754
+ const dx = focalPoint.x - seat.x;
3755
+ const dy = focalPoint.y - seat.y;
3756
+ const distU = Math.hypot(dx, dy);
3757
+ const distM = Math.max(2, distU * UNIT);
3758
+ const sky = ctx.createLinearGradient(0, 0, 0, H);
3759
+ sky.addColorStop(0, "#05070c");
3760
+ sky.addColorStop(0.42, "#11172a");
3761
+ sky.addColorStop(0.5, "#1a2238");
3762
+ sky.addColorStop(0.56, "#10141f");
3763
+ sky.addColorStop(1, "#07090f");
3764
+ ctx.fillStyle = sky;
3765
+ ctx.fillRect(0, 0, W, H);
3766
+ const stageHalfYaw = Math.min(80, Math.atan2(4, distM) * 180 / Math.PI);
3767
+ const stageTopPitch = Math.min(45, Math.atan2(5, distM) * 180 / Math.PI);
3768
+ const stageBasePitch = Math.max(-30, -Math.atan2(1.1, distM) * 180 / Math.PI);
3769
+ const sx0 = yawToX(-stageHalfYaw);
3770
+ const sx1 = yawToX(stageHalfYaw);
3771
+ const sy0 = pitchToY(stageTopPitch);
3772
+ const sy1 = pitchToY(stageBasePitch);
3773
+ const glow = ctx.createRadialGradient(W / 2, (sy0 + sy1) / 2, 10, W / 2, (sy0 + sy1) / 2, (sx1 - sx0) * 1.1);
3774
+ glow.addColorStop(0, "rgba(129, 140, 248, 0.5)");
3775
+ glow.addColorStop(0.5, "rgba(99, 102, 241, 0.16)");
3776
+ glow.addColorStop(1, "rgba(99, 102, 241, 0)");
3777
+ ctx.fillStyle = glow;
3778
+ ctx.fillRect(sx0 - (sx1 - sx0) * 0.6, sy0 - (sy1 - sy0) * 1.2, (sx1 - sx0) * 2.2, (sy1 - sy0) * 3.4);
3779
+ ctx.fillStyle = "#242c44";
3780
+ ctx.fillRect(sx0, sy0, sx1 - sx0, sy1 - sy0);
3781
+ const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);
3782
+ backdrop.addColorStop(0, "#7c5cff");
3783
+ backdrop.addColorStop(0.5, "#e1447a");
3784
+ backdrop.addColorStop(1, "#f59e0b");
3785
+ ctx.globalAlpha = 0.75;
3786
+ ctx.fillStyle = backdrop;
3787
+ const inset = (sx1 - sx0) * 0.06;
3788
+ ctx.fillRect(sx0 + inset, sy0 + (sy1 - sy0) * 0.12, sx1 - sx0 - inset * 2, (sy1 - sy0) * 0.62);
3789
+ ctx.globalAlpha = 1;
3790
+ ctx.fillStyle = "#0d1119";
3791
+ ctx.fillRect(sx0, sy1 - (sy1 - sy0) * 0.1, sx1 - sx0, (sy1 - sy0) * 0.1);
3792
+ const performerH = (sy1 - sy0) * 0.45;
3793
+ ctx.fillStyle = "rgba(8, 10, 16, 0.85)";
3794
+ for (const fx of [0.35, 0.5, 0.65]) {
3795
+ const px = sx0 + (sx1 - sx0) * fx;
3796
+ const py = sy1 - (sy1 - sy0) * 0.12;
3797
+ ctx.beginPath();
3798
+ ctx.arc(px, py - performerH * 0.82, performerH * 0.16, 0, Math.PI * 2);
3799
+ ctx.fill();
3800
+ ctx.fillRect(px - performerH * 0.14, py - performerH * 0.68, performerH * 0.28, performerH * 0.68);
3801
+ }
3802
+ ctx.globalAlpha = 0.14;
3803
+ ctx.fillStyle = "#c7d2fe";
3804
+ for (const fx of [0.3, 0.5, 0.7]) {
3805
+ const bx = sx0 + (sx1 - sx0) * fx;
3806
+ ctx.beginPath();
3807
+ ctx.moveTo(bx - 8, pitchToY(Math.min(60, stageTopPitch + 25)));
3808
+ ctx.lineTo(bx - (sx1 - sx0) * 0.09, sy1);
3809
+ ctx.lineTo(bx + (sx1 - sx0) * 0.09, sy1);
3810
+ ctx.lineTo(bx + 8, pitchToY(Math.min(60, stageTopPitch + 25)));
3811
+ ctx.closePath();
3812
+ ctx.fill();
3813
+ }
3814
+ ctx.globalAlpha = 1;
3815
+ ctx.fillStyle = "rgba(199, 210, 254, 0.8)";
3816
+ for (let i = 0; i < 26; i++) {
3817
+ const x = i / 26 * W;
3818
+ const y = pitchToY(55 + i % 3 * 6);
3819
+ ctx.beginPath();
3820
+ ctx.arc(x, y, 3.2, 0, Math.PI * 2);
3821
+ ctx.fill();
3822
+ }
3823
+ const stageBearing = Math.atan2(dx, -dy);
3824
+ ctx.fillStyle = "rgba(16, 20, 30, 0.95)";
3825
+ for (const other of neighborSeats) {
3826
+ if (other.id === seat.id) continue;
3827
+ const ox = other.x - seat.x;
3828
+ const oy = other.y - seat.y;
3829
+ const d = Math.hypot(ox, oy) * UNIT;
3830
+ if (d < 0.3 || d > 14) continue;
3831
+ const bearing = Math.atan2(ox, -oy) - stageBearing;
3832
+ const yaw = (bearing * 180 / Math.PI + 540) % 360 - 180;
3833
+ const headPitch = -Math.atan2(0.35, d) * 180 / Math.PI;
3834
+ const headR = Math.min(46, 260 / (d / UNIT / 24 + 1.2) / 4);
3835
+ const hx = yawToX(yaw);
3836
+ const hy = pitchToY(headPitch);
3837
+ ctx.beginPath();
3838
+ ctx.arc(hx, hy, headR, 0, Math.PI * 2);
3839
+ ctx.fill();
3840
+ ctx.beginPath();
3841
+ ctx.ellipse(hx, hy + headR * 1.4, headR * 1.7, headR * 0.9, 0, Math.PI, 0, true);
3842
+ ctx.fill();
3843
+ }
3844
+ const poleFade = ctx.createLinearGradient(0, 0, 0, H);
3845
+ poleFade.addColorStop(0, "rgba(0,0,0,0.85)");
3846
+ poleFade.addColorStop(0.12, "rgba(0,0,0,0)");
3847
+ poleFade.addColorStop(0.88, "rgba(0,0,0,0)");
3848
+ poleFade.addColorStop(1, "rgba(0,0,0,0.85)");
3849
+ ctx.fillStyle = poleFade;
3850
+ ctx.fillRect(0, 0, W, H);
3851
+ return { url: canvas.toDataURL("image/jpeg", 0.82), distanceM: Math.round(distM) };
3852
+ }
3853
+ var TW = 480;
3854
+ var TH = 270;
3855
+ var HALF_HFOV = 50;
3856
+ var HALF_VFOV = 30;
3857
+ var yawToTX = (yawDeg) => (yawDeg + HALF_HFOV) / (2 * HALF_HFOV) * TW;
3858
+ var pitchToTY = (pitchDeg) => (HALF_VFOV - pitchDeg) / (2 * HALF_VFOV) * TH;
3859
+ function generateSeatThumb(seat, focalPoint, _neighborSeats) {
3860
+ const canvas = document.createElement("canvas");
3861
+ canvas.width = TW;
3862
+ canvas.height = TH;
3863
+ const ctx = canvas.getContext("2d");
3864
+ const dx = focalPoint.x - seat.x;
3865
+ const dy = focalPoint.y - seat.y;
3866
+ const distM = Math.max(2, Math.hypot(dx, dy) * UNIT);
3867
+ const sky = ctx.createLinearGradient(0, 0, 0, TH);
3868
+ sky.addColorStop(0, "#05070c");
3869
+ sky.addColorStop(0.44, "#141b30");
3870
+ sky.addColorStop(0.5, "#1b2440");
3871
+ sky.addColorStop(0.58, "#10141f");
3872
+ sky.addColorStop(1, "#070910");
3873
+ ctx.fillStyle = sky;
3874
+ ctx.fillRect(0, 0, TW, TH);
3875
+ const stageHalfYaw = Math.min(HALF_HFOV - 2, Math.atan2(4, distM) * 180 / Math.PI);
3876
+ const stageTopPitch = Math.min(HALF_VFOV - 2, Math.atan2(5, distM) * 180 / Math.PI);
3877
+ const stageBasePitch = Math.max(-HALF_VFOV + 2, -Math.atan2(1.1, distM) * 180 / Math.PI);
3878
+ const sx0 = yawToTX(-stageHalfYaw);
3879
+ const sx1 = yawToTX(stageHalfYaw);
3880
+ const sy0 = pitchToTY(stageTopPitch);
3881
+ const sy1 = pitchToTY(stageBasePitch);
3882
+ const sw = sx1 - sx0;
3883
+ const sh = sy1 - sy0;
3884
+ const glow = ctx.createRadialGradient(TW / 2, (sy0 + sy1) / 2, 4, TW / 2, (sy0 + sy1) / 2, sw * 1.1);
3885
+ glow.addColorStop(0, "rgba(129,140,248,0.5)");
3886
+ glow.addColorStop(0.5, "rgba(99,102,241,0.15)");
3887
+ glow.addColorStop(1, "rgba(99,102,241,0)");
3888
+ ctx.fillStyle = glow;
3889
+ ctx.fillRect(sx0 - sw * 0.6, sy0 - sh * 1.2, sw * 2.2, sh * 3.4);
3890
+ ctx.fillStyle = "#242c44";
3891
+ ctx.fillRect(sx0, sy0, sw, sh);
3892
+ const backdrop = ctx.createLinearGradient(0, sy0, 0, sy1);
3893
+ backdrop.addColorStop(0, "#7c5cff");
3894
+ backdrop.addColorStop(0.5, "#e1447a");
3895
+ backdrop.addColorStop(1, "#f59e0b");
3896
+ ctx.globalAlpha = 0.78;
3897
+ ctx.fillStyle = backdrop;
3898
+ const inset = sw * 0.06;
3899
+ ctx.fillRect(sx0 + inset, sy0 + sh * 0.12, sw - inset * 2, sh * 0.62);
3900
+ ctx.globalAlpha = 1;
3901
+ ctx.fillStyle = "#0d1119";
3902
+ ctx.fillRect(sx0, sy1 - sh * 0.1, sw, sh * 0.1);
3903
+ const ph = sh * 0.45;
3904
+ ctx.fillStyle = "rgba(8,10,16,0.85)";
3905
+ for (const fx of [0.35, 0.5, 0.65]) {
3906
+ const px = sx0 + sw * fx;
3907
+ const py = sy1 - sh * 0.12;
3908
+ ctx.beginPath();
3909
+ ctx.arc(px, py - ph * 0.82, ph * 0.16, 0, Math.PI * 2);
3910
+ ctx.fill();
3911
+ ctx.fillRect(px - ph * 0.14, py - ph * 0.68, ph * 0.28, ph * 0.68);
3912
+ }
3913
+ ctx.globalAlpha = 0.15;
3914
+ ctx.fillStyle = "#c7d2fe";
3915
+ for (const fx of [0.3, 0.5, 0.7]) {
3916
+ const bx = sx0 + sw * fx;
3917
+ ctx.beginPath();
3918
+ ctx.moveTo(bx - 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));
3919
+ ctx.lineTo(bx - sw * 0.09, sy1);
3920
+ ctx.lineTo(bx + sw * 0.09, sy1);
3921
+ ctx.lineTo(bx + 5, pitchToTY(Math.min(HALF_VFOV, stageTopPitch + 18)));
3922
+ ctx.closePath();
3923
+ ctx.fill();
3924
+ }
3925
+ ctx.globalAlpha = 1;
3926
+ ctx.fillStyle = "rgba(199,210,254,0.75)";
3927
+ for (let i = 0; i < 8; i++) {
3928
+ ctx.beginPath();
3929
+ ctx.arc((i + 0.5) / 8 * TW, pitchToTY(HALF_VFOV - 4 - i % 2 * 3), 2.2, 0, Math.PI * 2);
3930
+ ctx.fill();
3931
+ }
3932
+ ctx.fillStyle = "rgba(10,13,20,0.9)";
3933
+ ctx.fillRect(0, TH - 26, TW, 26);
3934
+ ctx.fillStyle = "rgba(30,37,54,0.9)";
3935
+ for (let i = 0; i < 9; i++) ctx.fillRect(i * (TW / 9) + 6, TH - 22, TW / 9 - 12, 14);
3936
+ return { url: canvas.toDataURL("image/jpeg", 0.8), distanceM: Math.round(distM) };
3937
+ }
3938
+
3721
3939
  // src/i18n/bundles.ts
3722
3940
  var LOADERS = {
3723
3941
  es: () => Promise.resolve().then(() => (init_es(), es_exports)).then((m) => ({ default: m.es })),
@@ -3771,6 +3989,8 @@ async function loadLocale(code) {
3771
3989
  gaAreasOf,
3772
3990
  gaUnitLabel,
3773
3991
  gaUnitLabels,
3992
+ generateSeatPanorama,
3993
+ generateSeatThumb,
3774
3994
  getLocale,
3775
3995
  hiddenObjectIds,
3776
3996
  isGaUnitLabel,