@seatlayer/js 0.45.0 → 0.47.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/channelsMode-33ZLORVF.js +13 -0
- package/dist/channelsMode-33ZLORVF.js.map +1 -0
- package/dist/chunk-CF5MS7UR.js +2543 -0
- package/dist/chunk-CF5MS7UR.js.map +1 -0
- package/dist/chunk-DMEFXZIL.js +3198 -0
- package/dist/chunk-DMEFXZIL.js.map +1 -0
- package/dist/chunk-X2R4AQSZ.js +323 -0
- package/dist/chunk-X2R4AQSZ.js.map +1 -0
- package/dist/{hostedCheckout-PLHKPT6W.js → hostedCheckout-SHQCWN5Y.js} +27 -4
- package/dist/hostedCheckout-SHQCWN5Y.js.map +1 -0
- package/dist/index.cjs +9855 -9412
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -1391
- package/dist/index.d.ts +102 -1391
- package/dist/index.js +417 -6003
- package/dist/index.js.map +1 -1
- package/dist/manager-CAIPkUYl.d.cts +1419 -0
- package/dist/manager-CAIPkUYl.d.ts +1419 -0
- package/dist/manager.cjs +6069 -0
- package/dist/manager.cjs.map +1 -0
- package/dist/manager.d.cts +2 -0
- package/dist/manager.d.ts +2 -0
- package/dist/manager.js +14 -0
- package/dist/manager.js.map +1 -0
- package/package.json +20 -2
- package/dist/hostedCheckout-PLHKPT6W.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { PickerSeat, RendererViewMode, SeatHoverDetails, PickerTransport,
|
|
1
|
+
import { PickerSeat, RendererViewMode, SeatHoverDetails, PickerTransport, PickerMapTheme } from '@seatlayer/core';
|
|
2
2
|
export { ExpandedSeat, SeatHoverDetails } from '@seatlayer/core';
|
|
3
|
+
import { C as ChannelListResult, a as ChannelAllocationPage, b as ChannelRecord, A as AssignmentResult, c as ChannelPreviewProjection, d as ChannelAccessIntent, e as AccessLinkReveal, f as AccessLinkStatusRecord, g as ChannelSeatStatus, B as BucketRow } from './manager-CAIPkUYl.js';
|
|
4
|
+
export { h as ACCESS_LINK_DEFAULTS, i as AccessIntentForbidsDetails, j as AccessLinkRecord, k as AccessLinkState, l as AccessLinkStatus, m as ArchiveBlockedDetails, n as AssignmentBuckets, o as AssignmentDropDetails, p as ChannelAccessSummary, q as ChannelAuditEntry, r as ChannelAuditPage, s as ChannelCounts, t as ChannelState, u as ControlRoomActivityEntry, v as ControlRoomSectionMetric, w as ControlRoomSnapshot, I as IntentSwitchBlockedDetails, L as LogEntry, x as LogPage, M as ManageApi, y as ManageApiError, P as PUBLIC_CHANNEL_ID, z as PUBLIC_CHANNEL_NAME, R as ReportByStatus, D as ReportCategoryMeta, E as ReportCategoryRow, F as ReportResult, S as SeatManager, G as SeatManagerActionResult, H as SeatManagerActivity, J as SeatManagerCapability, K as SeatManagerConnection, N as SeatManagerMode, O as SeatManagerOptions, Q as SeatManagerTallies, T as SelectionSourceRow, U as accessIntentDescription, V as accessIntentLabel, W as accessLine, X as accessLinkBadge, Y as accessLinkErrorCopy, Z as accessLinkIsLive, _ as accessLinkPolicyLines, $ as bucketRows, a0 as dropReviewRows, a1 as intentForbidsCopy, a2 as intentSwitchBlockedCopy, a3 as isPublicChannelId, a4 as markerLetter, a5 as markerOf, a6 as mutationCount, a7 as needsMoveConfirmation, a8 as planAssignment, a9 as retryAfterCopy, aa as selectionSources, ab as stateBadge, ac as suggestMarker } from './manager-CAIPkUYl.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Buyer access context — the browser half of the Sales Channels contract
|
|
@@ -230,10 +232,21 @@ interface RealtimeSink {
|
|
|
230
232
|
/** Apply a batch of label→status changes. Implementations must paint this as
|
|
231
233
|
* ONE pass, not one pass per label (motion system §4 rule 2). */
|
|
232
234
|
applyStatuses(changes: StatusChange[]): void;
|
|
235
|
+
/**
|
|
236
|
+
* Paint a COMPLETE projection — the default plus the units that differ.
|
|
237
|
+
*
|
|
238
|
+
* Every case that cannot be expressed as a bounded diff (the first snapshot,
|
|
239
|
+
* or a changed default) still arrives as a whole authoritative projection: the
|
|
240
|
+
* client holds it, it just has no way to hand it over. This is that way, and
|
|
241
|
+
* where a sink provides it the {@link resync} round trip is skipped entirely.
|
|
242
|
+
*
|
|
243
|
+
* Optional, so an older sink keeps working unchanged.
|
|
244
|
+
*/
|
|
245
|
+
applyProjection?(projection: Projection): void;
|
|
233
246
|
/** Re-pull authoritative state over the scoped HTTP route. Used when a frame
|
|
234
247
|
* cannot be diffed against what we hold (first snapshot, or the scope's
|
|
235
248
|
* default itself changed, which redefines every unit we were never told
|
|
236
|
-
* about). */
|
|
249
|
+
* about), and the sink cannot take a whole projection. */
|
|
237
250
|
resync(): void | Promise<void>;
|
|
238
251
|
/** Section availability changed (channel-agnostic; identical for every scope). */
|
|
239
252
|
onSections?(hidden: string[], closed: string[]): void;
|
|
@@ -243,7 +256,7 @@ interface RealtimeSink {
|
|
|
243
256
|
activeHolds: number;
|
|
244
257
|
}): void;
|
|
245
258
|
}
|
|
246
|
-
interface SubscribeTicket
|
|
259
|
+
interface SubscribeTicket {
|
|
247
260
|
ticket?: string;
|
|
248
261
|
/** Exactly what to hand `new WebSocket(url, protocols)`, per protocol doc §3. */
|
|
249
262
|
protocols?: string[];
|
|
@@ -254,7 +267,7 @@ interface BuyerRealtimeOptions {
|
|
|
254
267
|
sink: RealtimeSink;
|
|
255
268
|
/** Mint a one-use ticket for THIS connection attempt. Returns null for the
|
|
256
269
|
* anonymous public case (no ticket needed). Throwing stops the client. */
|
|
257
|
-
mintTicket?: () => Promise<SubscribeTicket
|
|
270
|
+
mintTicket?: () => Promise<SubscribeTicket | null>;
|
|
258
271
|
/** Typed access states. 4401 arrives here as `revoked`. */
|
|
259
272
|
onAccessUnavailable?: (event: BuyerAccessUnavailableEvent) => void;
|
|
260
273
|
/** Test seam. Defaults to the global WebSocket. */
|
|
@@ -462,6 +475,19 @@ interface OrderStatusResult {
|
|
|
462
475
|
currency: string;
|
|
463
476
|
amountFormatted: string;
|
|
464
477
|
seatCount: number;
|
|
478
|
+
eventName?: string | null;
|
|
479
|
+
venue?: string | null;
|
|
480
|
+
startsAt?: number | null;
|
|
481
|
+
tickets?: Array<{
|
|
482
|
+
label: string;
|
|
483
|
+
token: string;
|
|
484
|
+
status: 'issued' | 'checked_in' | 'void';
|
|
485
|
+
checkedInAt: number | null;
|
|
486
|
+
}>;
|
|
487
|
+
/** Hosted ticket page — the durable re-entry point after the modal closes. */
|
|
488
|
+
ticketUrl?: string;
|
|
489
|
+
/** Printable PDF, one page per ticket. */
|
|
490
|
+
pdfUrl?: string;
|
|
465
491
|
}
|
|
466
492
|
interface PubApiOptions {
|
|
467
493
|
/**
|
|
@@ -1144,6 +1170,24 @@ interface SeatPickerTheme {
|
|
|
1144
1170
|
logoUrl?: string;
|
|
1145
1171
|
/** Brand/event fallback name for the monogram. */
|
|
1146
1172
|
brandName?: string;
|
|
1173
|
+
/**
|
|
1174
|
+
* The DRAWN MAP, which the tokens above deliberately do not reach.
|
|
1175
|
+
*
|
|
1176
|
+
* Everything else on this interface is CSS: it re-inks panels, buttons and
|
|
1177
|
+
* the sidebar. The seat map is a canvas, painted from the chart document's
|
|
1178
|
+
* own `ChartTheme`, so a host could re-ink the whole widget and still be
|
|
1179
|
+
* looking at somebody else's dark venue in the middle of it (which is exactly
|
|
1180
|
+
* what SeatLayer's own light event-page palettes did, found 2026-08-07).
|
|
1181
|
+
*
|
|
1182
|
+
* Nested rather than flattened because `background` already means the
|
|
1183
|
+
* WIDGET's background here and the canvas ground is a different surface —
|
|
1184
|
+
* two things one word cannot carry.
|
|
1185
|
+
*
|
|
1186
|
+
* Set it only when you can vouch for the result: these colours are drawn
|
|
1187
|
+
* behind and beside live seat statuses (held, sold, selected), and the map is
|
|
1188
|
+
* the one part of this widget a buyer has to be able to read.
|
|
1189
|
+
*/
|
|
1190
|
+
map?: PickerMapTheme;
|
|
1147
1191
|
}
|
|
1148
1192
|
interface SeatPickerOptions {
|
|
1149
1193
|
/** CSS selector or element to mount into. Omit when using SeatPicker.open(). */
|
|
@@ -1222,10 +1266,19 @@ interface SeatPickerOptions {
|
|
|
1222
1266
|
* on a phone. Offering 3D there is offering a stall. A host that knows its
|
|
1223
1267
|
* audience can raise this; the ceiling goes away when seat streaming lands. */
|
|
1224
1268
|
max3DSeats?: number;
|
|
1269
|
+
/**
|
|
1270
|
+
* Fires when the buyer enters/leaves 3D or targets a seat there. Hosts can
|
|
1271
|
+
* mirror this small, non-sensitive state into a shareable URL.
|
|
1272
|
+
*/
|
|
1273
|
+
onBuyerViewChange?: (state: {
|
|
1274
|
+
view: 'map' | 'venue3d';
|
|
1275
|
+
seatId?: string;
|
|
1276
|
+
}) => void;
|
|
1225
1277
|
/**
|
|
1226
1278
|
* Optional analytics sink for the widget's own journey events. Currently emits
|
|
1227
1279
|
* the 3D venue-view journey (`3d_opened`, `3d_orbit_engaged`, `3d_seat_picked`,
|
|
1228
|
-
* `3d_cinematic_played`/`_skipped`/`_cancelled`,
|
|
1280
|
+
* `3d_cinematic_played`/`_skipped`/`_cancelled`, panorama outcomes, and WebGL
|
|
1281
|
+
* context loss/recovery)
|
|
1229
1282
|
* with `{ surface: 'buyer' }` merged into the props. A throwing sink never
|
|
1230
1283
|
* breaks the widget. Route it to your product analytics (e.g. PostHog). */
|
|
1231
1284
|
onAnalytics?: (event: string, props: Record<string, unknown>) => void;
|
|
@@ -1536,8 +1589,8 @@ declare class SeatPicker {
|
|
|
1536
1589
|
/**
|
|
1537
1590
|
* Eager sightline preview for the confirm card: the organizer's real view
|
|
1538
1591
|
* photo, or — only when the chart has an actual stage to look at — a generated
|
|
1539
|
-
* forward view plus an
|
|
1540
|
-
* chart both the distance
|
|
1592
|
+
* forward view plus an approximate distance-to-stage line. On a stageless
|
|
1593
|
+
* chart both the distance claim and the generic stage silhouette are
|
|
1541
1594
|
* invented promises, so we suppress them; a real attached photo always shows.
|
|
1542
1595
|
* (OV-52)
|
|
1543
1596
|
*/
|
|
@@ -1589,6 +1642,7 @@ declare class SeatPicker {
|
|
|
1589
1642
|
private reportFramedHeight;
|
|
1590
1643
|
/** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */
|
|
1591
1644
|
private toggleFullscreen;
|
|
1645
|
+
private syncFullscreenButtons;
|
|
1592
1646
|
/**
|
|
1593
1647
|
* Native element-fullscreen was unavailable or rejected. When framed, a CSS
|
|
1594
1648
|
* `.sl-fs` overlay can't escape the iframe, so we ask the host page to pin us
|
|
@@ -1897,6 +1951,43 @@ declare class SeatPicker {
|
|
|
1897
1951
|
private rowShort;
|
|
1898
1952
|
private updateTooltip;
|
|
1899
1953
|
getSelection(): PickerSeat[];
|
|
1954
|
+
/**
|
|
1955
|
+
* Re-ink the DRAWN MAP after mount, so the canvas can follow a page palette
|
|
1956
|
+
* the host did not know at construction time.
|
|
1957
|
+
*
|
|
1958
|
+
* Deliberately narrower than the `theme` option: it takes only the map half.
|
|
1959
|
+
* The chrome half is CSS custom properties, which a host restyles from its
|
|
1960
|
+
* own stylesheet without asking the widget for anything — and a host that
|
|
1961
|
+
* used both mechanisms at once would have two things writing one token. This
|
|
1962
|
+
* method exists for the half CSS genuinely cannot reach: pixels Konva draws.
|
|
1963
|
+
*
|
|
1964
|
+
* The rebuild is the controller's (`setMapTheme`), which repaints statuses
|
|
1965
|
+
* from the map already in memory and restores the selection, so a buyer
|
|
1966
|
+
* mid-pick keeps their seats and no round trip is spent. A no-op when the
|
|
1967
|
+
* colours have not changed; safe to call on every render.
|
|
1968
|
+
*/
|
|
1969
|
+
setMapTheme(map: PickerMapTheme | null): void;
|
|
1970
|
+
/**
|
|
1971
|
+
* Replace the host pricing override AFTER mount, and repaint everything that
|
|
1972
|
+
* shows a price.
|
|
1973
|
+
*
|
|
1974
|
+
* WHY IT CANNOT JUST BE A MOUNT OPTION. The prices a host knows are often not
|
|
1975
|
+
* the prices it knows AT MOUNT: SeatLayer's own event page learns them from
|
|
1976
|
+
* `GET /pub/events/:key/availability`, a separate cached read that lands a
|
|
1977
|
+
* round trip after the map does — deliberately, because the map is not
|
|
1978
|
+
* allowed to wait on it. Remounting the widget to hand it new options would
|
|
1979
|
+
* tear down a live hold, so the override is settable in place.
|
|
1980
|
+
*
|
|
1981
|
+
* The prices themselves are still the SERVER'S. This method takes an answer;
|
|
1982
|
+
* it never derives one. Nothing here re-reads a release, a window or a quota
|
|
1983
|
+
* — see `paidPrice`, the one funnel every displayed price flows through, and
|
|
1984
|
+
* note that the checkout handoff's line items do not come from here at all:
|
|
1985
|
+
* they are priced by the worker from its own hold. So the worst a wrong call
|
|
1986
|
+
* to this method can do is misprint a price, never mischarge one.
|
|
1987
|
+
*
|
|
1988
|
+
* A no-op when the map is unchanged, so a host may call it on every poll.
|
|
1989
|
+
*/
|
|
1990
|
+
setPricing(pricing: SeatPickerPricing | undefined): void;
|
|
1900
1991
|
/** Current colorblind-safe render state, resolved from the stored buyer
|
|
1901
1992
|
* preference at mount. Host chrome (e.g. the Designer preview) reads this to
|
|
1902
1993
|
* surface the state rather than rendering colorblind colors silently. */
|
|
@@ -1923,10 +2014,7 @@ declare class SeatPicker {
|
|
|
1923
2014
|
*
|
|
1924
2015
|
* Entering `'venue3d'` with `opts.flyToSeatId` runs the cinematic tour: the
|
|
1925
2016
|
* camera flies to the seat and holds in the live scene (a chip offers the
|
|
1926
|
-
* 360° view-from-seat)
|
|
1927
|
-
* the widget enters 3D and auto-flies the camera to that seat, dissolving into
|
|
1928
|
-
* its view-from-seat panorama (the same chain as tapping "See the view from
|
|
1929
|
-
* here" on a seat's confirm card). When the widget is **already** in the 3D
|
|
2017
|
+
* 360° view-from-seat). When the widget is **already** in the 3D
|
|
1930
2018
|
* view, the camera simply flies to the requested seat — the GL scene is not
|
|
1931
2019
|
* torn down or rebuilt, so there is no flash or re-entry.
|
|
1932
2020
|
*
|
|
@@ -1935,7 +2023,7 @@ declare class SeatPicker {
|
|
|
1935
2023
|
*
|
|
1936
2024
|
* @param view `'map'` for the flat picker, `'venue3d'` for the 3D venue.
|
|
1937
2025
|
* @param opts.flyToSeatId When entering (or already in) `'venue3d'`, the seat
|
|
1938
|
-
* id to fly the camera to — cinematic →
|
|
2026
|
+
* id to fly the camera to — cinematic → live seat view.
|
|
1939
2027
|
* Ignored when `view` is `'map'`.
|
|
1940
2028
|
*
|
|
1941
2029
|
* @example
|
|
@@ -1944,6 +2032,7 @@ declare class SeatPicker {
|
|
|
1944
2032
|
*/
|
|
1945
2033
|
setBuyerView(view: 'map' | 'venue3d', opts?: {
|
|
1946
2034
|
flyToSeatId?: string;
|
|
2035
|
+
resetView?: boolean;
|
|
1947
2036
|
}): void;
|
|
1948
2037
|
/** SeatStatus → the view3d palette state. Selection is layered separately. */
|
|
1949
2038
|
private seatState3dFor;
|
|
@@ -2056,1384 +2145,6 @@ interface AttachPickerFrameOptions {
|
|
|
2056
2145
|
*/
|
|
2057
2146
|
declare function attachPickerFrame(iframe: HTMLIFrameElement, opts?: AttachPickerFrameOptions): () => void;
|
|
2058
2147
|
|
|
2059
|
-
/**
|
|
2060
|
-
* Sales-channel planning — the pure, DOM-free half of Channels mode.
|
|
2061
|
-
*
|
|
2062
|
-
* Everything here is deterministic and testable without a canvas: the marker
|
|
2063
|
-
* palette, the mixed-source selection summary, the LOCAL staged preview of an
|
|
2064
|
-
* assignment, and the bucket rows the Review sheet renders.
|
|
2065
|
-
*
|
|
2066
|
-
* The local preview deliberately produces the SAME `AssignmentBuckets` shape the
|
|
2067
|
-
* server returns from `POST /channels/assignments`. There is no dry-run endpoint,
|
|
2068
|
-
* so the review sheet is drawn from this local computation and then REDRAWN from
|
|
2069
|
-
* the authoritative server response after Apply. One renderer, two sources —
|
|
2070
|
-
* which is why the shapes must match exactly.
|
|
2071
|
-
*
|
|
2072
|
-
* Spec: sales-channels-product-ux-spec §8.4–8.5.
|
|
2073
|
-
*/
|
|
2074
|
-
/**
|
|
2075
|
-
* Public sale is a built-in pseudo-channel. The server's sentinel for it is the
|
|
2076
|
-
* literal string `'public'` — it is what `GET /channels` returns as
|
|
2077
|
-
* `publicSale.id`, what `GET /channels/allocation` reports for an unallocated
|
|
2078
|
-
* unit, and what `POST /channels/assignments` accepts (alongside `null`) as the
|
|
2079
|
-
* target meaning "send these back to public sale".
|
|
2080
|
-
*
|
|
2081
|
-
* This constant was `''` until 2026-08-02, which silently made every public unit
|
|
2082
|
-
* look like an unknown PRIVATE channel to `planAssignment` and `markerOf` — the
|
|
2083
|
-
* cause of the Review sheet's phantom "moved out of another channel" line and
|
|
2084
|
-
* the rail's "?" marker. Keep it byte-identical to the server's
|
|
2085
|
-
* `eventChannels.PUBLIC_CHANNEL_ID`.
|
|
2086
|
-
*/
|
|
2087
|
-
declare const PUBLIC_CHANNEL_ID = "public";
|
|
2088
|
-
declare const PUBLIC_CHANNEL_NAME = "Public sale";
|
|
2089
|
-
/** True for every spelling of "public sale" a worker may hand us. */
|
|
2090
|
-
declare function isPublicChannelId(id: string | null | undefined): boolean;
|
|
2091
|
-
type ChannelState = 'active' | 'paused' | 'archived';
|
|
2092
|
-
/** Physical inventory status, as the manage surface speaks it. */
|
|
2093
|
-
type ChannelSeatStatus = 'free' | 'held' | 'booked' | 'blocked';
|
|
2094
|
-
interface ChannelCounts {
|
|
2095
|
-
allocated: number;
|
|
2096
|
-
free: number;
|
|
2097
|
-
held: number;
|
|
2098
|
-
booked: number;
|
|
2099
|
-
blocked: number;
|
|
2100
|
-
units: number;
|
|
2101
|
-
}
|
|
2102
|
-
/** Buyer-access intents the server stores per channel. */
|
|
2103
|
-
type ChannelAccessIntent = 'none' | 'internal' | 'server' | 'hosted_link';
|
|
2104
|
-
/**
|
|
2105
|
-
* Buyer-access summary on a channel row. Shipped by the access hardening branch
|
|
2106
|
-
* (merged to app main). Still optional in this type: a worker that predates the
|
|
2107
|
-
* merge simply omits it and the rail reads "—" rather than inventing a state.
|
|
2108
|
-
*/
|
|
2109
|
-
interface ChannelAccessSummary {
|
|
2110
|
-
intent?: ChannelAccessIntent | string;
|
|
2111
|
-
hasActiveGrants?: boolean;
|
|
2112
|
-
lastMintAt?: number | null;
|
|
2113
|
-
/** Free-text detail (partner host, who paused it) when the server offers one. */
|
|
2114
|
-
detail?: string | null;
|
|
2115
|
-
}
|
|
2116
|
-
interface ChannelRecord {
|
|
2117
|
-
id: string;
|
|
2118
|
-
name: string;
|
|
2119
|
-
color: string | null;
|
|
2120
|
-
marker: string | null;
|
|
2121
|
-
externalRef: string | null;
|
|
2122
|
-
state: ChannelState;
|
|
2123
|
-
archiveDestination: string | null;
|
|
2124
|
-
createdAt: number;
|
|
2125
|
-
updatedAt: number;
|
|
2126
|
-
archivedAt: number | null;
|
|
2127
|
-
counts: ChannelCounts;
|
|
2128
|
-
access?: ChannelAccessSummary | null;
|
|
2129
|
-
}
|
|
2130
|
-
interface PublicSaleChannel {
|
|
2131
|
-
/** `'public'` on every shipped worker; typed loosely so an older build that
|
|
2132
|
-
* still answers `''` is normalised rather than rejected. */
|
|
2133
|
-
id: string;
|
|
2134
|
-
name: string;
|
|
2135
|
-
state: 'active';
|
|
2136
|
-
counts: ChannelCounts;
|
|
2137
|
-
access?: ChannelAccessSummary | null;
|
|
2138
|
-
}
|
|
2139
|
-
interface ChannelListResult {
|
|
2140
|
-
assignmentVersion: number;
|
|
2141
|
-
publicSale: PublicSaleChannel;
|
|
2142
|
-
channels: ChannelRecord[];
|
|
2143
|
-
}
|
|
2144
|
-
interface AssignmentBucketCount {
|
|
2145
|
-
count: number;
|
|
2146
|
-
}
|
|
2147
|
-
interface AssignmentSkippedBucket extends AssignmentBucketCount {
|
|
2148
|
-
labels: string[];
|
|
2149
|
-
truncated: boolean;
|
|
2150
|
-
}
|
|
2151
|
-
interface AssignmentBuckets {
|
|
2152
|
-
changedFromPublic: AssignmentBucketCount;
|
|
2153
|
-
movedFromOtherChannel: AssignmentBucketCount & {
|
|
2154
|
-
channels: Array<{
|
|
2155
|
-
channelId: string;
|
|
2156
|
-
name: string | null;
|
|
2157
|
-
count: number;
|
|
2158
|
-
}>;
|
|
2159
|
-
};
|
|
2160
|
-
alreadyInTarget: AssignmentBucketCount;
|
|
2161
|
-
skippedHeld: AssignmentSkippedBucket;
|
|
2162
|
-
skippedBooked: AssignmentSkippedBucket;
|
|
2163
|
-
/** Requested labels that are not inventory in this event. */
|
|
2164
|
-
notFound: AssignmentSkippedBucket;
|
|
2165
|
-
}
|
|
2166
|
-
interface AssignmentResult {
|
|
2167
|
-
ok: true;
|
|
2168
|
-
targetChannelId: string;
|
|
2169
|
-
assignmentVersion: number;
|
|
2170
|
-
requested: number;
|
|
2171
|
-
applied: number;
|
|
2172
|
-
buckets: AssignmentBuckets;
|
|
2173
|
-
}
|
|
2174
|
-
interface ArchiveBlockedDetails {
|
|
2175
|
-
activeHolds?: number;
|
|
2176
|
-
heldUnits?: number;
|
|
2177
|
-
latestHoldExpiresAt?: number | null;
|
|
2178
|
-
retryAfterMs?: number;
|
|
2179
|
-
}
|
|
2180
|
-
/**
|
|
2181
|
-
* Clamp any marker text down to the ONE uppercase character every surface draws.
|
|
2182
|
-
*
|
|
2183
|
-
* The server stores `marker` as free text (it only length-caps it), so a channel
|
|
2184
|
-
* created outside this widget can carry "star" or "VIP". The comp's marker chip
|
|
2185
|
-
* is a single glyph: taking two characters ("ST") overflows the 22px chip and
|
|
2186
|
-
* stops reading as a letter. Non-letter leading characters (an emoji, a digit,
|
|
2187
|
-
* punctuation) are skipped in favour of the first real letter.
|
|
2188
|
-
*/
|
|
2189
|
-
declare function markerLetter(raw: string | null | undefined, fallback: string): string;
|
|
2190
|
-
/**
|
|
2191
|
-
* Suggest a marker for a new channel: the first letter of its name when that
|
|
2192
|
-
* letter is still free, otherwise the next unused letter. Deterministic so the
|
|
2193
|
-
* Create dialog's preview matches what actually gets stored.
|
|
2194
|
-
*/
|
|
2195
|
-
declare function suggestMarker(name: string, taken: Iterable<string>): {
|
|
2196
|
-
letter: string;
|
|
2197
|
-
color: string;
|
|
2198
|
-
};
|
|
2199
|
-
/** The letter + color a channel actually renders with (server value wins). */
|
|
2200
|
-
declare function markerOf(channel: {
|
|
2201
|
-
id: string;
|
|
2202
|
-
name: string;
|
|
2203
|
-
marker?: string | null;
|
|
2204
|
-
color?: string | null;
|
|
2205
|
-
}, index?: number): {
|
|
2206
|
-
letter: string;
|
|
2207
|
-
color: string;
|
|
2208
|
-
};
|
|
2209
|
-
/** One line of the rail's mixed-source selection summary (§8.4). */
|
|
2210
|
-
interface SelectionSourceRow {
|
|
2211
|
-
channelId: string;
|
|
2212
|
-
name: string;
|
|
2213
|
-
count: number;
|
|
2214
|
-
}
|
|
2215
|
-
/**
|
|
2216
|
-
* Group the current selection by the channel each unit is allocated to today.
|
|
2217
|
-
* Public sale is listed first; the rest follow in list order so the rail's
|
|
2218
|
-
* ordering never jitters as the selection changes.
|
|
2219
|
-
*/
|
|
2220
|
-
declare function selectionSources(labels: string[], allocation: Map<string, string>, list: ChannelListResult | null): SelectionSourceRow[];
|
|
2221
|
-
/**
|
|
2222
|
-
* The LOCAL staged preview of "move these labels to this channel".
|
|
2223
|
-
*
|
|
2224
|
-
* Mirrors the DO's rules exactly (eventChannels.applyAssignment):
|
|
2225
|
-
* - a unit already in the target is `alreadyInTarget`, whatever its status;
|
|
2226
|
-
* - otherwise held and booked units are skipped and never rewritten;
|
|
2227
|
-
* - otherwise a public unit is `changedFromPublic`, a private one is
|
|
2228
|
-
* `movedFromOtherChannel` (itemised per source);
|
|
2229
|
-
* - a label that is not inventory in this event is `notFound`.
|
|
2230
|
-
*
|
|
2231
|
-
* Every requested label lands in exactly one bucket — the property the Review
|
|
2232
|
-
* sheet's "every selected seat is in exactly one line" promise depends on.
|
|
2233
|
-
*/
|
|
2234
|
-
declare function planAssignment(input: {
|
|
2235
|
-
labels: string[];
|
|
2236
|
-
targetChannelId: string;
|
|
2237
|
-
allocation: Map<string, string>;
|
|
2238
|
-
statusOf: (label: string) => ChannelSeatStatus | undefined;
|
|
2239
|
-
nameOf: (channelId: string) => string | null;
|
|
2240
|
-
}): AssignmentBuckets;
|
|
2241
|
-
/** Units this plan will actually mutate — what the Apply button counts. */
|
|
2242
|
-
declare function mutationCount(buckets: AssignmentBuckets): number;
|
|
2243
|
-
/** True when moving inventory out of another PRIVATE channel — §8.5 requires an
|
|
2244
|
-
* explicit confirmation line for exactly this case. */
|
|
2245
|
-
declare function needsMoveConfirmation(buckets: AssignmentBuckets): boolean;
|
|
2246
|
-
interface BucketRow {
|
|
2247
|
-
kind: 'add' | 'move' | 'same' | 'skip';
|
|
2248
|
-
icon: string;
|
|
2249
|
-
count: number;
|
|
2250
|
-
text: string;
|
|
2251
|
-
why?: string;
|
|
2252
|
-
/** Sampled seat labels for a skipped bucket, when the server sent any. */
|
|
2253
|
-
peek?: string;
|
|
2254
|
-
}
|
|
2255
|
-
/**
|
|
2256
|
-
* Render-ready rows for the Review sheet. The comp shows five lines; the server
|
|
2257
|
-
* carries a sixth bucket (`notFound`) which is emitted only when it is non-zero,
|
|
2258
|
-
* so a normal review still reads exactly like the approved design.
|
|
2259
|
-
*
|
|
2260
|
-
* Empty buckets are dropped — a zero line is noise, not honesty.
|
|
2261
|
-
*/
|
|
2262
|
-
declare function bucketRows(buckets: AssignmentBuckets, targetName: string): BucketRow[];
|
|
2263
|
-
/**
|
|
2264
|
-
* "try again in ~N minutes" for the archive-blocked-by-holds 409 (§8.8).
|
|
2265
|
-
* Rounds up so the organizer never comes back one tick early.
|
|
2266
|
-
*/
|
|
2267
|
-
declare function retryAfterCopy(details: ArchiveBlockedDetails | null | undefined): string;
|
|
2268
|
-
/** The access line under a channel row. Falls back to "—" before the hardening
|
|
2269
|
-
* branch lands the `access` field, never to a guess. */
|
|
2270
|
-
declare function accessLine(access: ChannelAccessSummary | null | undefined): string;
|
|
2271
|
-
/**
|
|
2272
|
-
* The name of each sale route, WORD FOR WORD as the server says it.
|
|
2273
|
-
*
|
|
2274
|
-
* `eventChannels.ts` builds its refusal sentences from an `INTENT_LABEL` map
|
|
2275
|
-
* with exactly these four strings. Diverging here would mean the picker calls a
|
|
2276
|
-
* route one thing and the refusal it produces calls it another, so these are
|
|
2277
|
-
* copied deliberately rather than paraphrased.
|
|
2278
|
-
*/
|
|
2279
|
-
declare function accessIntentLabel(intent: ChannelAccessIntent): string;
|
|
2280
|
-
/**
|
|
2281
|
-
* What choosing this route actually DOES, now that the server enforces it.
|
|
2282
|
-
*
|
|
2283
|
-
* Written against the enforcement matrix, not against intent: each route opens
|
|
2284
|
-
* exactly one way to reach a buyer and refuses the other three, so each sentence
|
|
2285
|
-
* says both halves. The old copy for these values promised nothing and delivered
|
|
2286
|
-
* nothing; it was deleted in 0.42.0 and is not coming back.
|
|
2287
|
-
*/
|
|
2288
|
-
declare function accessIntentDescription(intent: ChannelAccessIntent): string;
|
|
2289
|
-
/** `channel_access_intent_forbids` (409) — the route this channel declares is
|
|
2290
|
-
* not the one the action needed. */
|
|
2291
|
-
interface AccessIntentForbidsDetails {
|
|
2292
|
-
channelId?: string;
|
|
2293
|
-
accessIntent?: ChannelAccessIntent | string;
|
|
2294
|
-
/** The route the refused action arrived on: `hosted_link` | `server` | `staff` | `public`. */
|
|
2295
|
-
route?: string;
|
|
2296
|
-
}
|
|
2297
|
-
/**
|
|
2298
|
-
* The refusal, said as a decision the organizer can act on.
|
|
2299
|
-
*
|
|
2300
|
-
* The server's own sentence stops at "…so it cannot be sold through a buyer
|
|
2301
|
-
* link" — true, but it leaves the reader to work out what to do. This adds the
|
|
2302
|
-
* second half: which route to switch to. The code itself is never shown.
|
|
2303
|
-
*/
|
|
2304
|
-
declare function intentForbidsCopy(details: AccessIntentForbidsDetails | null | undefined): string;
|
|
2305
|
-
/** `channel_intent_switch_blocked` (409) — buyers are inside the current route. */
|
|
2306
|
-
interface IntentSwitchBlockedDetails {
|
|
2307
|
-
channelId?: string;
|
|
2308
|
-
from?: ChannelAccessIntent | string;
|
|
2309
|
-
to?: ChannelAccessIntent | string;
|
|
2310
|
-
liveAccessLinks?: number;
|
|
2311
|
-
activeSessions?: number;
|
|
2312
|
-
acknowledgeWith?: {
|
|
2313
|
-
acknowledgeLiveAccess?: boolean;
|
|
2314
|
-
};
|
|
2315
|
-
}
|
|
2316
|
-
/**
|
|
2317
|
-
* What is live right now, and what acknowledging would do to it.
|
|
2318
|
-
*
|
|
2319
|
-
* Both halves are checked against the server rather than guessed: an
|
|
2320
|
-
* acknowledged switch REVOKES the channel's hosted links (redemption refuses
|
|
2321
|
-
* from that moment, so a link left listed as active would be a door the
|
|
2322
|
-
* management surface advertises and the buyer path denies), and deliberately
|
|
2323
|
-
* LEAVES buyer sessions and their holds alone — nobody is thrown out of a
|
|
2324
|
-
* checkout. Sessions cap at 12 hours (30 minutes by default) and no new ones can
|
|
2325
|
-
* be minted, so the old route drains on its own.
|
|
2326
|
-
*/
|
|
2327
|
-
declare function intentSwitchBlockedCopy(details: IntentSwitchBlockedDetails | null | undefined): {
|
|
2328
|
-
headline: string;
|
|
2329
|
-
consequences: string[];
|
|
2330
|
-
};
|
|
2331
|
-
/** Lifecycle the server stores. `rotated` means a newer link replaced this one. */
|
|
2332
|
-
type AccessLinkState = 'active' | 'revoked' | 'rotated';
|
|
2333
|
-
/** What the organizer surface renders: `state`, unless an active link has run
|
|
2334
|
-
* out of time or out of redemptions. Never a capability, never a hash. */
|
|
2335
|
-
type AccessLinkStatus = AccessLinkState | 'expired' | 'exhausted';
|
|
2336
|
-
/**
|
|
2337
|
-
* One hosted link, exactly as `GET …/access-links` projects it.
|
|
2338
|
-
*
|
|
2339
|
-
* There is deliberately NO `url` and NO `capability` field here — the listing
|
|
2340
|
-
* route does not return them, no other route returns them, and this type must
|
|
2341
|
-
* not tempt a caller into believing otherwise. The secret exists in exactly one
|
|
2342
|
-
* place for exactly one moment: the create/rotate response (`AccessLinkReveal`).
|
|
2343
|
-
*/
|
|
2344
|
-
interface AccessLinkRecord {
|
|
2345
|
-
id: string;
|
|
2346
|
-
channelId: string;
|
|
2347
|
-
label: string | null;
|
|
2348
|
-
includePublic: boolean;
|
|
2349
|
-
expiresAt: number;
|
|
2350
|
-
maxRedemptions: number;
|
|
2351
|
-
redemptions: number;
|
|
2352
|
-
/** Guest-weighted per-buyer ceiling handed to every session this link mints. */
|
|
2353
|
-
maxQuantity: number;
|
|
2354
|
-
sessionTtlSeconds: number;
|
|
2355
|
-
state: AccessLinkState;
|
|
2356
|
-
status: AccessLinkStatus;
|
|
2357
|
-
createdAt: number;
|
|
2358
|
-
createdBy: string | null;
|
|
2359
|
-
revokedAt: number | null;
|
|
2360
|
-
lastRedeemedAt: number | null;
|
|
2361
|
-
/** Rotation lineage: the link this replaced, and the one that replaced it. */
|
|
2362
|
-
rotatedFrom: string | null;
|
|
2363
|
-
rotatedTo: string | null;
|
|
2364
|
-
}
|
|
2365
|
-
/** A listed link, with the live session count the rotate dialog needs to state
|
|
2366
|
-
* "N buyers got in with this link and still have access". */
|
|
2367
|
-
interface AccessLinkStatusRecord extends AccessLinkRecord {
|
|
2368
|
-
activeSessions?: number;
|
|
2369
|
-
}
|
|
2370
|
-
/**
|
|
2371
|
-
* The ONE-TIME reveal. `url` and `capability` are on the wire exactly once, in
|
|
2372
|
-
* the create/rotate response, and are unrecoverable afterwards: SeatLayer stores
|
|
2373
|
-
* only a hash. Nothing may persist this — see `ChannelsMode.revealLink`.
|
|
2374
|
-
*/
|
|
2375
|
-
interface AccessLinkReveal {
|
|
2376
|
-
link: AccessLinkRecord;
|
|
2377
|
-
url: string;
|
|
2378
|
-
capability: string;
|
|
2379
|
-
revealedOnce: true;
|
|
2380
|
-
/** Rotation only: the link that just stopped working, and how many live buyer
|
|
2381
|
-
* sessions from it were ended (0 when the organizer let them finish). */
|
|
2382
|
-
previous?: AccessLinkRecord;
|
|
2383
|
-
endedSessions?: number;
|
|
2384
|
-
}
|
|
2385
|
-
/**
|
|
2386
|
-
* Owner-set defaults for a new link. Expiry is NOT here: "when the event starts"
|
|
2387
|
-
* is the server's own default (it knows `starts_at`; the cockpit does not), so
|
|
2388
|
-
* the create form expresses that choice by omitting `expiresAt` entirely rather
|
|
2389
|
-
* than by guessing a timestamp the server would then have to correct.
|
|
2390
|
-
*/
|
|
2391
|
-
declare const ACCESS_LINK_DEFAULTS: {
|
|
2392
|
-
readonly maxRedemptions: 100;
|
|
2393
|
-
readonly maxQuantity: 4;
|
|
2394
|
-
};
|
|
2395
|
-
/** Plain-language state badge for a hosted link (§9: no internal vocabulary). */
|
|
2396
|
-
declare function accessLinkBadge(link: Pick<AccessLinkRecord, 'status' | 'state'>): {
|
|
2397
|
-
text: string;
|
|
2398
|
-
kind: 'active' | 'paused' | 'archived';
|
|
2399
|
-
};
|
|
2400
|
-
/** Only an `active` link can be rotated or revoked; the server agrees (409
|
|
2401
|
-
* `access_link_not_active`), so the buttons are absent rather than failing. */
|
|
2402
|
-
declare function accessLinkIsLive(link: Pick<AccessLinkRecord, 'status' | 'state'>): boolean;
|
|
2403
|
-
/**
|
|
2404
|
-
* The policy an organizer is agreeing to, in one list. Used by BOTH the reveal
|
|
2405
|
-
* (what you just created) and the status card (what is live), so the two can
|
|
2406
|
-
* never drift into describing the same link differently.
|
|
2407
|
-
*/
|
|
2408
|
-
declare function accessLinkPolicyLines(link: AccessLinkRecord): Array<{
|
|
2409
|
-
k: string;
|
|
2410
|
-
v: string;
|
|
2411
|
-
}>;
|
|
2412
|
-
/**
|
|
2413
|
-
* Plain language for a refused hosted-link call.
|
|
2414
|
-
*
|
|
2415
|
-
* The PLATFORM BOUNDS live on the server (60s–180d expiry, 1–10 000 redemptions,
|
|
2416
|
-
* 1–100 seats per buyer, 20 live links per channel) and the server states them
|
|
2417
|
-
* in `message`. We surface that sentence rather than re-encoding the numbers
|
|
2418
|
-
* here, so the client can never disagree with the rule it is reporting.
|
|
2419
|
-
*/
|
|
2420
|
-
declare function accessLinkErrorCopy(err: {
|
|
2421
|
-
code?: string;
|
|
2422
|
-
serverMessage?: string;
|
|
2423
|
-
status?: number;
|
|
2424
|
-
details?: Record<string, unknown>;
|
|
2425
|
-
} | null | undefined): string;
|
|
2426
|
-
/**
|
|
2427
|
-
* The chart-update refusal `channel_assignment_would_drop` (409) deliberately
|
|
2428
|
-
* mirrors the Apply skipped buckets, so ONE review component renders both.
|
|
2429
|
-
* This adapts it into the same `BucketRow[]` the Review sheet already draws.
|
|
2430
|
-
*/
|
|
2431
|
-
interface AssignmentDropDetails {
|
|
2432
|
-
droppedUnits?: number;
|
|
2433
|
-
channels?: Array<{
|
|
2434
|
-
channelId: string;
|
|
2435
|
-
name: string | null;
|
|
2436
|
-
count: number;
|
|
2437
|
-
labels?: string[];
|
|
2438
|
-
truncated?: boolean;
|
|
2439
|
-
}>;
|
|
2440
|
-
acknowledgeWith?: string;
|
|
2441
|
-
}
|
|
2442
|
-
declare function dropReviewRows(details: AssignmentDropDetails | null | undefined): BucketRow[];
|
|
2443
|
-
/** Plain-language state badge text (§9: no internal vocabulary on user surfaces). */
|
|
2444
|
-
declare function stateBadge(state: ChannelState | 'builtin'): string;
|
|
2445
|
-
|
|
2446
|
-
/**
|
|
2447
|
-
* Organizer manage-surface client for workers/api (the `/v1/events/:key/*`
|
|
2448
|
-
* inventory routes + the public realtime channel). Companion to api.ts (the
|
|
2449
|
-
* buyer `/pub/*` client) — kept separate because the manage surface is
|
|
2450
|
-
* token-authed (Bearer) and cross-origin from the CMS:
|
|
2451
|
-
*
|
|
2452
|
-
* - Writes + reports send `Authorization: Bearer <token>` where the token is
|
|
2453
|
-
* a short-lived, event-scoped organizer manage token (`mse_…`, minted by
|
|
2454
|
-
* NestJS) OR a tenant secret key (`sk_…`). Both are accepted by the worker's
|
|
2455
|
-
* `eitherAuth` on block / unblock / unblock-all / unbook / hold-ttl / report
|
|
2456
|
-
* / log. The Authorization header also exempts the call from the worker's
|
|
2457
|
-
* cookie-CSRF gate, so no extra client header is needed.
|
|
2458
|
-
* - `credentials: 'omit'` — there is no session cookie; the CMS runs
|
|
2459
|
-
* cross-origin. The worker's credentialed CORS still echoes the CMS origin.
|
|
2460
|
-
* - `/pub/events/:key/chart` stays public: geometry is the same map buyers
|
|
2461
|
-
* see. The seat STATE reads are not. `/pub/.../objects` and an unticketed
|
|
2462
|
-
* `/pub/.../subscribe` both answer with the BUYER projection, which shows
|
|
2463
|
-
* inventory the caller may not buy as a neutral `blocked` — so an organizer
|
|
2464
|
-
* reading them sees its own channel allocations as blocked seats. Both now
|
|
2465
|
-
* go through the token: `/v1/events/:key/objects` for the snapshot, and a
|
|
2466
|
-
* `/v1/events/:key/subscribe-tickets` mint for the socket's scope.
|
|
2467
|
-
*
|
|
2468
|
-
* `box-book` is intentionally omitted for M1 (box office ships in M2, and the
|
|
2469
|
-
* route is still session-only server-side).
|
|
2470
|
-
*/
|
|
2471
|
-
|
|
2472
|
-
/** One page of the organizer-only label → channel projection. */
|
|
2473
|
-
interface ChannelAllocationPage {
|
|
2474
|
-
assignmentVersion: number;
|
|
2475
|
-
allocations: Array<{
|
|
2476
|
-
label: string;
|
|
2477
|
-
channelId: string;
|
|
2478
|
-
}>;
|
|
2479
|
-
nextAfterLabel: string | null;
|
|
2480
|
-
}
|
|
2481
|
-
interface ChannelAuditEntry {
|
|
2482
|
-
id: number;
|
|
2483
|
-
at: number;
|
|
2484
|
-
actor: string | null;
|
|
2485
|
-
action: string;
|
|
2486
|
-
channelId: string | null;
|
|
2487
|
-
assignmentVersion: number;
|
|
2488
|
-
before: unknown;
|
|
2489
|
-
after: unknown;
|
|
2490
|
-
reason: string | null;
|
|
2491
|
-
}
|
|
2492
|
-
interface ChannelAuditPage {
|
|
2493
|
-
entries: ChannelAuditEntry[];
|
|
2494
|
-
nextBefore: number | null;
|
|
2495
|
-
}
|
|
2496
|
-
/**
|
|
2497
|
-
* Buyer projection for a preview audience — the same scoped server view the
|
|
2498
|
-
* buyer SDK receives. When an audience cannot be previewed (a paused or
|
|
2499
|
-
* archived channel), the server answers `{available:false, unavailable:[…]}`
|
|
2500
|
-
* and the UI shows the real paused/unavailable landing state instead of
|
|
2501
|
-
* rendering those seats as eligible.
|
|
2502
|
-
*
|
|
2503
|
-
* Fields stay optional: a worker that predates the hardening merge 404s here,
|
|
2504
|
-
* and Channels mode says the preview needs a newer server rather than faking a
|
|
2505
|
-
* projection client-side.
|
|
2506
|
-
*/
|
|
2507
|
-
interface ChannelPreviewProjection {
|
|
2508
|
-
available?: boolean;
|
|
2509
|
-
unavailable?: Array<{
|
|
2510
|
-
channelId: string;
|
|
2511
|
-
state: 'paused' | 'archived' | string;
|
|
2512
|
-
}>;
|
|
2513
|
-
channelIds?: string[];
|
|
2514
|
-
includePublic?: boolean;
|
|
2515
|
-
/** Labels this audience may buy. Everything else renders as ONE neutral
|
|
2516
|
-
* unavailable state so preview never leaks which channel holds a seat. */
|
|
2517
|
-
eligible?: string[];
|
|
2518
|
-
counts?: {
|
|
2519
|
-
eligible?: number;
|
|
2520
|
-
free?: number;
|
|
2521
|
-
held?: number;
|
|
2522
|
-
booked?: number;
|
|
2523
|
-
};
|
|
2524
|
-
}
|
|
2525
|
-
declare class ManageApiError extends Error {
|
|
2526
|
-
status: number;
|
|
2527
|
-
code?: string;
|
|
2528
|
-
/** Present when a block/unbook 409s because seats were just taken. */
|
|
2529
|
-
conflicts?: {
|
|
2530
|
-
label: string;
|
|
2531
|
-
reason?: string;
|
|
2532
|
-
}[];
|
|
2533
|
-
/**
|
|
2534
|
-
* Structured refusal detail. The channel routes use it for the two 409s a UI
|
|
2535
|
-
* must render rather than merely report: `channel_archive_blocked_by_holds`
|
|
2536
|
-
* carries {activeHolds, heldUnits, latestHoldExpiresAt, retryAfterMs}, and
|
|
2537
|
-
* `channel_assignment_conflict` carries the current assignmentVersion.
|
|
2538
|
-
*/
|
|
2539
|
-
details?: Record<string, unknown>;
|
|
2540
|
-
/**
|
|
2541
|
-
* The server's own human sentence, when it sent one. `message` is the machine
|
|
2542
|
-
* code (that is what `error` carries), so a UI that wants to state a PLATFORM
|
|
2543
|
-
* RULE — "redemptions must be between 1 and 10 000" — reads this instead of
|
|
2544
|
-
* re-encoding the bound locally and risking disagreement with the server.
|
|
2545
|
-
*/
|
|
2546
|
-
serverMessage?: string;
|
|
2547
|
-
constructor(status: number, message: string, code?: string, conflicts?: {
|
|
2548
|
-
label: string;
|
|
2549
|
-
reason?: string;
|
|
2550
|
-
}[], details?: Record<string, unknown>, serverMessage?: string);
|
|
2551
|
-
}
|
|
2552
|
-
interface ReportByStatus {
|
|
2553
|
-
free: number;
|
|
2554
|
-
held: number;
|
|
2555
|
-
booked: number;
|
|
2556
|
-
not_for_sale: number;
|
|
2557
|
-
}
|
|
2558
|
-
interface ReportCategoryRow {
|
|
2559
|
-
category: string;
|
|
2560
|
-
total: number;
|
|
2561
|
-
free: number;
|
|
2562
|
-
held: number;
|
|
2563
|
-
booked: number;
|
|
2564
|
-
not_for_sale: number;
|
|
2565
|
-
/** Exact sum of booked unit_price snapshots, in major currency units. */
|
|
2566
|
-
bookedRevenue: number;
|
|
2567
|
-
}
|
|
2568
|
-
interface ReportCategoryMeta {
|
|
2569
|
-
key: string;
|
|
2570
|
-
label: string;
|
|
2571
|
-
color: string;
|
|
2572
|
-
price: number;
|
|
2573
|
-
}
|
|
2574
|
-
interface ReportResult {
|
|
2575
|
-
report: {
|
|
2576
|
-
byStatus: ReportByStatus;
|
|
2577
|
-
byCategory: ReportCategoryRow[];
|
|
2578
|
-
bySection?: ControlRoomSectionMetric[];
|
|
2579
|
-
};
|
|
2580
|
-
event: {
|
|
2581
|
-
key: string;
|
|
2582
|
-
name: string;
|
|
2583
|
-
seatTotal: number;
|
|
2584
|
-
currency?: string;
|
|
2585
|
-
};
|
|
2586
|
-
categories: ReportCategoryMeta[];
|
|
2587
|
-
}
|
|
2588
|
-
interface ControlRoomSectionMetric {
|
|
2589
|
-
sectionId: string;
|
|
2590
|
-
sectionLabel: string;
|
|
2591
|
-
zoneId: string | null;
|
|
2592
|
-
total: number;
|
|
2593
|
-
free: number;
|
|
2594
|
-
held: number;
|
|
2595
|
-
booked: number;
|
|
2596
|
-
not_for_sale: number;
|
|
2597
|
-
bookedRevenue: number;
|
|
2598
|
-
}
|
|
2599
|
-
/** Recent seat-state change safe for an event:view control-room grant. Full
|
|
2600
|
-
* audit references remain available only through the event:reports log API. */
|
|
2601
|
-
interface ControlRoomActivityEntry {
|
|
2602
|
-
id: number;
|
|
2603
|
-
at: number;
|
|
2604
|
-
action: string;
|
|
2605
|
-
labels: string[];
|
|
2606
|
-
}
|
|
2607
|
-
interface ControlRoomSnapshot {
|
|
2608
|
-
version: number;
|
|
2609
|
-
currency: string;
|
|
2610
|
-
totals: {
|
|
2611
|
-
free: number;
|
|
2612
|
-
held: number;
|
|
2613
|
-
booked: number;
|
|
2614
|
-
blocked: number;
|
|
2615
|
-
};
|
|
2616
|
-
revenue: {
|
|
2617
|
-
gross: number;
|
|
2618
|
-
bySection: ControlRoomSectionMetric[];
|
|
2619
|
-
};
|
|
2620
|
-
velocity: {
|
|
2621
|
-
windowMinutes: number;
|
|
2622
|
-
bySection: Array<{
|
|
2623
|
-
sectionId: string;
|
|
2624
|
-
netBooked: number;
|
|
2625
|
-
grossRevenue: number;
|
|
2626
|
-
previousNetBooked: number;
|
|
2627
|
-
trend: 'rising' | 'steady' | 'cooling';
|
|
2628
|
-
}>;
|
|
2629
|
-
};
|
|
2630
|
-
presence: {
|
|
2631
|
-
shoppingSessions: number;
|
|
2632
|
-
activeHolds: number;
|
|
2633
|
-
};
|
|
2634
|
-
/** Present on workers that support reload-safe activity hydration. */
|
|
2635
|
-
activity?: ControlRoomActivityEntry[];
|
|
2636
|
-
event: {
|
|
2637
|
-
key: string;
|
|
2638
|
-
name: string;
|
|
2639
|
-
seatTotal: number;
|
|
2640
|
-
currency?: string;
|
|
2641
|
-
};
|
|
2642
|
-
}
|
|
2643
|
-
interface LogEntry {
|
|
2644
|
-
id: number;
|
|
2645
|
-
at: number;
|
|
2646
|
-
action: string;
|
|
2647
|
-
labels: string[];
|
|
2648
|
-
ref: string | null;
|
|
2649
|
-
}
|
|
2650
|
-
interface LogPage {
|
|
2651
|
-
entries: LogEntry[];
|
|
2652
|
-
nextBefore: number | null;
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* A one-use WebSocket subscribe ticket. `protocols` is exactly what to hand
|
|
2656
|
-
* `new WebSocket(url, protocols)` — the ticket rides in `Sec-WebSocket-Protocol`
|
|
2657
|
-
* because a browser socket cannot carry an Authorization header and a bearer
|
|
2658
|
-
* must never travel in a URL.
|
|
2659
|
-
*/
|
|
2660
|
-
interface SubscribeTicket {
|
|
2661
|
-
ticket: string;
|
|
2662
|
-
expiresAt: number;
|
|
2663
|
-
protocol: string;
|
|
2664
|
-
protocols: string[];
|
|
2665
|
-
}
|
|
2666
|
-
interface PubObjectsResult {
|
|
2667
|
-
/** Every non-free seat's status keyed by label (free seats omitted). */
|
|
2668
|
-
seats: Record<string, string>;
|
|
2669
|
-
hidden?: string[];
|
|
2670
|
-
closed?: string[];
|
|
2671
|
-
updatedAt: number;
|
|
2672
|
-
}
|
|
2673
|
-
interface PubChartResult {
|
|
2674
|
-
event: {
|
|
2675
|
-
key: string;
|
|
2676
|
-
name: string;
|
|
2677
|
-
status?: string;
|
|
2678
|
-
venue?: string | null;
|
|
2679
|
-
startsAt?: number | null;
|
|
2680
|
-
currency?: string;
|
|
2681
|
-
mode?: string;
|
|
2682
|
-
};
|
|
2683
|
-
doc: ChartDoc;
|
|
2684
|
-
}
|
|
2685
|
-
/**
|
|
2686
|
-
* Bound to one apiBase + one event-scoped token. Rebuild (or `setToken`) when a
|
|
2687
|
-
* token is re-minted on 401.
|
|
2688
|
-
*/
|
|
2689
|
-
declare class ManageApi {
|
|
2690
|
-
private base;
|
|
2691
|
-
private token;
|
|
2692
|
-
constructor(apiBase: string, token: string);
|
|
2693
|
-
/** Swap the Bearer token in place (SeatManager re-mints on 401). */
|
|
2694
|
-
setToken(token: string): void;
|
|
2695
|
-
private auth;
|
|
2696
|
-
private pub;
|
|
2697
|
-
/** The chart geometry. Genuinely public — it is the same map buyers see. */
|
|
2698
|
-
chart(key: string): Promise<PubChartResult>;
|
|
2699
|
-
/**
|
|
2700
|
-
* The ORGANIZER's seat map: physical state, token-authed.
|
|
2701
|
-
*
|
|
2702
|
-
* This used to read `/pub/events/:key/objects` with no credential, which
|
|
2703
|
-
* answers with the BUYER projection — every unit the caller may not buy
|
|
2704
|
-
* collapses to a neutral `blocked`. An anonymous caller may buy only Public
|
|
2705
|
-
* sale inventory, so the cockpit rendered every channel-allocated seat as
|
|
2706
|
-
* blocked and then computed its KPIs, sell-through and (worse) its
|
|
2707
|
-
* block/unblock target sets from that. `/v1/events/:key/objects` returns the
|
|
2708
|
-
* unprojected snapshot the control-room read model already trusts.
|
|
2709
|
-
*/
|
|
2710
|
-
objects(key: string): Promise<PubObjectsResult>;
|
|
2711
|
-
/**
|
|
2712
|
-
* Exchange the manage token for a one-use organizer socket ticket.
|
|
2713
|
-
*
|
|
2714
|
-
* A browser `WebSocket` cannot send an Authorization header, so the socket's
|
|
2715
|
-
* scope is established here, over ordinary HTTPS. Without it the DO treats a
|
|
2716
|
-
* manager socket as an anonymous public buyer and projects its deltas — so a
|
|
2717
|
-
* hold inside a private allocation is structurally suppressed and the map
|
|
2718
|
-
* drifts away from the truth `objects()` just established.
|
|
2719
|
-
*
|
|
2720
|
-
* Tickets are single-redemption and expire in ~30s: mint one per connect.
|
|
2721
|
-
*/
|
|
2722
|
-
subscribeTicket(key: string): Promise<SubscribeTicket>;
|
|
2723
|
-
socketUrl(key: string): string;
|
|
2724
|
-
/** Take FREE seats off sale in one batched call. Optional `releaseAt` (epoch
|
|
2725
|
-
* ms, future) auto-returns them to sale; `reason` tags the block (M3 uses it).
|
|
2726
|
-
* Throws ManageApiError 409 (conflicts) if any seat was just taken. */
|
|
2727
|
-
block(key: string, labels: string[], opts?: {
|
|
2728
|
-
releaseAt?: number;
|
|
2729
|
-
reason?: string;
|
|
2730
|
-
}): Promise<{
|
|
2731
|
-
ok: true;
|
|
2732
|
-
blocked: string[];
|
|
2733
|
-
}>;
|
|
2734
|
-
/** Return specific blocked seats to sale (one batched call). */
|
|
2735
|
-
unblock(key: string, labels: string[]): Promise<{
|
|
2736
|
-
ok: true;
|
|
2737
|
-
unblocked: string[];
|
|
2738
|
-
}>;
|
|
2739
|
-
/** Return every blocked seat to sale; resolves with the freed count. */
|
|
2740
|
-
unblockAll(key: string): Promise<{
|
|
2741
|
-
ok: true;
|
|
2742
|
-
freed: number;
|
|
2743
|
-
}>;
|
|
2744
|
-
/** Cancel bookings — return BOOKED seats to free (credit not refunded).
|
|
2745
|
-
* Guarded by the original booking reference. */
|
|
2746
|
-
unbook(key: string, labels: string[], bookingRef: string): Promise<{
|
|
2747
|
-
ok: true;
|
|
2748
|
-
unbooked: string[];
|
|
2749
|
-
}>;
|
|
2750
|
-
/** Set (ms, clamped 1–60 min server-side) or clear (null) the hold TTL. */
|
|
2751
|
-
setHoldTtl(key: string, holdTtlMs: number | null): Promise<{
|
|
2752
|
-
ok: true;
|
|
2753
|
-
holdTtlMs: number | null;
|
|
2754
|
-
}>;
|
|
2755
|
-
/** The organizer's current per section/zone availability windows (needs
|
|
2756
|
-
* `event:view`). Ids absent from `rules` are open / on sale. */
|
|
2757
|
-
availability(key: string): Promise<{
|
|
2758
|
-
rules: Record<string, AvailabilityRule>;
|
|
2759
|
-
}>;
|
|
2760
|
-
/** Replace the availability windows for a set of section/zone ids (needs
|
|
2761
|
-
* `event:block`). Ids absent from `rules` become open / on sale; a zone rule
|
|
2762
|
-
* cascades to its sections. The worker derives each id's seat labels, so
|
|
2763
|
-
* `labels` on the sent rules is best-effort. Resolves with the authoritative
|
|
2764
|
-
* effective `hidden` set (a due rule may fire at once) and the server-cleaned
|
|
2765
|
-
* `rules` map (fired timed/threshold windows dropped). */
|
|
2766
|
-
setAvailability(key: string, rules: Record<string, AvailabilityRule>): Promise<{
|
|
2767
|
-
ok: true;
|
|
2768
|
-
hidden: string[];
|
|
2769
|
-
rules: Record<string, AvailabilityRule>;
|
|
2770
|
-
}>;
|
|
2771
|
-
/** Allocation list with exact per-channel counts. `includeArchived` adds the
|
|
2772
|
-
* read-only archived rows behind the rail's "Show archived" control. */
|
|
2773
|
-
channels(key: string, opts?: {
|
|
2774
|
-
includeArchived?: boolean;
|
|
2775
|
-
}): Promise<ChannelListResult>;
|
|
2776
|
-
/** One page of the label → channel map that paints the allocation overlay.
|
|
2777
|
-
* Paged by label; follow `nextAfterLabel` until it is null. */
|
|
2778
|
-
channelAllocation(key: string, opts?: {
|
|
2779
|
-
afterLabel?: string;
|
|
2780
|
-
limit?: number;
|
|
2781
|
-
}): Promise<ChannelAllocationPage>;
|
|
2782
|
-
channelAudit(key: string, opts?: {
|
|
2783
|
-
limit?: number;
|
|
2784
|
-
before?: number;
|
|
2785
|
-
}): Promise<ChannelAuditPage>;
|
|
2786
|
-
createChannel(key: string, input: {
|
|
2787
|
-
name: string;
|
|
2788
|
-
color?: string | null;
|
|
2789
|
-
marker?: string | null;
|
|
2790
|
-
externalRef?: string | null;
|
|
2791
|
-
}): Promise<{
|
|
2792
|
-
ok: true;
|
|
2793
|
-
channel: ChannelRecord;
|
|
2794
|
-
}>;
|
|
2795
|
-
renameChannel(key: string, channelId: string, name: string): Promise<{
|
|
2796
|
-
ok: true;
|
|
2797
|
-
channel: ChannelRecord;
|
|
2798
|
-
}>;
|
|
2799
|
-
setChannelPaused(key: string, channelId: string, paused: boolean): Promise<{
|
|
2800
|
-
ok: true;
|
|
2801
|
-
channel: ChannelRecord;
|
|
2802
|
-
}>;
|
|
2803
|
-
/** Archive with a mandatory destination for the remaining allocation.
|
|
2804
|
-
* Throws ManageApiError 409 `channel_archive_blocked_by_holds` while any hold
|
|
2805
|
-
* is live; `err.details` carries the exact counts + retry window. */
|
|
2806
|
-
archiveChannel(key: string, channelId: string, destination: string | null): Promise<{
|
|
2807
|
-
ok: true;
|
|
2808
|
-
channel: ChannelRecord;
|
|
2809
|
-
assignmentVersion: number;
|
|
2810
|
-
moved: number;
|
|
2811
|
-
}>;
|
|
2812
|
-
/**
|
|
2813
|
-
* Versioned Apply. A stale `assignmentVersion` mutates NOTHING and throws
|
|
2814
|
-
* ManageApiError 409 `channel_assignment_conflict` — the caller keeps its
|
|
2815
|
-
* selection and offers "Refresh and review". There is no dry-run: the review
|
|
2816
|
-
* sheet previews locally, this call returns the authoritative buckets.
|
|
2817
|
-
*/
|
|
2818
|
-
applyChannelAssignment(key: string, input: {
|
|
2819
|
-
targetChannelId: string | null;
|
|
2820
|
-
labels: string[];
|
|
2821
|
-
assignmentVersion: number;
|
|
2822
|
-
}): Promise<AssignmentResult>;
|
|
2823
|
-
/**
|
|
2824
|
-
* Read-only buyer projection for an audience (§8.6) — the SAME scoped server
|
|
2825
|
-
* view the buyer SDK receives, never a local approximation.
|
|
2826
|
-
*
|
|
2827
|
-
* Ships on the access-hardening branch. Older workers 404/405 here; callers
|
|
2828
|
-
* MUST feature-detect and quietly say the preview needs a newer server rather
|
|
2829
|
-
* than faking a projection client-side.
|
|
2830
|
-
*/
|
|
2831
|
-
channelPreview(key: string, channelIds: string[], opts?: {
|
|
2832
|
-
includePublic?: boolean;
|
|
2833
|
-
}): Promise<ChannelPreviewProjection>;
|
|
2834
|
-
/**
|
|
2835
|
-
* Choose which sale route this channel opens.
|
|
2836
|
-
*
|
|
2837
|
-
* Since the server's 2026-08-06 change this is AUTHORIZATION, not a label:
|
|
2838
|
-
* exactly one of the four routes may mint buyer access for the channel and the
|
|
2839
|
-
* other three refuse with 409 `channel_access_intent_forbids`. The default is
|
|
2840
|
-
* `none`, which refuses all four — so a route has to be declared before any
|
|
2841
|
-
* buyer-facing action on the channel can succeed.
|
|
2842
|
-
*
|
|
2843
|
-
* Switching the route while buyers are already inside the current one is
|
|
2844
|
-
* refused with 409 `channel_intent_switch_blocked`, whose `details` name what
|
|
2845
|
-
* is live (`liveAccessLinks`, `activeSessions`). Retry with
|
|
2846
|
-
* `acknowledgeLiveAccess: true`: hosted links on the channel are revoked,
|
|
2847
|
-
* while sessions already minted keep their holds and drain on their own.
|
|
2848
|
-
* `intentSwitch` is present on the response ONLY when the switch disturbed
|
|
2849
|
-
* something, so the ordinary case stays the two-key body it has always been.
|
|
2850
|
-
*/
|
|
2851
|
-
setChannelAccessIntent(key: string, channelId: string, accessIntent: ChannelAccessIntent, opts?: {
|
|
2852
|
-
acknowledgeLiveAccess?: boolean;
|
|
2853
|
-
reason?: string;
|
|
2854
|
-
}): Promise<{
|
|
2855
|
-
ok: true;
|
|
2856
|
-
channel: ChannelRecord;
|
|
2857
|
-
intentSwitch?: {
|
|
2858
|
-
closedLinks: number;
|
|
2859
|
-
keptSessions: number;
|
|
2860
|
-
};
|
|
2861
|
-
}>;
|
|
2862
|
-
/**
|
|
2863
|
-
* Mint a hosted access link. The 201 is the ONE and ONLY time `url` and
|
|
2864
|
-
* `capability` exist outside the buyer's browser — SeatLayer keeps a hash, so
|
|
2865
|
-
* there is no route, cache, or support escalation that can produce this string
|
|
2866
|
-
* again. Callers must reveal it immediately and then let it go.
|
|
2867
|
-
*
|
|
2868
|
-
* Every omitted field takes the server's default: expiry = when the event
|
|
2869
|
-
* starts, 100 redemptions, 4 seats per buyer, this channel's allocation only.
|
|
2870
|
-
* Platform bounds are enforced server-side and reported as 422 with the rule
|
|
2871
|
-
* spelled out in `ManageApiError.serverMessage`.
|
|
2872
|
-
*
|
|
2873
|
-
* NOT a side effect any more. This used to SET the channel's access intent to
|
|
2874
|
-
* `hosted_link`; since 2026-08-06 it REQUIRES it, and a channel declaring any
|
|
2875
|
-
* other route refuses with 409 `channel_access_intent_forbids`. Callers must
|
|
2876
|
-
* declare the route first — `ChannelsMode` does exactly that before it
|
|
2877
|
-
* creates, so a first buyer link on a fresh channel is still one gesture.
|
|
2878
|
-
*/
|
|
2879
|
-
createAccessLink(key: string, channelId: string, input?: {
|
|
2880
|
-
label?: string | null;
|
|
2881
|
-
/** Absolute epoch ms. Omit for "when the event starts". */
|
|
2882
|
-
expiresAt?: number;
|
|
2883
|
-
maxRedemptions?: number;
|
|
2884
|
-
maxQuantity?: number;
|
|
2885
|
-
includePublic?: boolean;
|
|
2886
|
-
}): Promise<AccessLinkReveal>;
|
|
2887
|
-
/** Status only — label, expiry, redemptions, per-buyer cap, lineage, and the
|
|
2888
|
-
* live session count. Never the url, never the capability. Needs `:view`. */
|
|
2889
|
-
accessLinks(key: string, channelId: string): Promise<{
|
|
2890
|
-
links: AccessLinkStatusRecord[];
|
|
2891
|
-
}>;
|
|
2892
|
-
/**
|
|
2893
|
-
* Rotate — the ONLY recovery for a link nobody kept. The old URL stops opening
|
|
2894
|
-
* immediately and the response is a fresh one-time reveal.
|
|
2895
|
-
*
|
|
2896
|
-
* `endActiveSessions` is REQUIRED, not defaulted: the organizer must say
|
|
2897
|
-
* whether buyers already inside finish their checkout or lose access now. The
|
|
2898
|
-
* server answers 422 `end_active_sessions_required` if it is omitted, and that
|
|
2899
|
-
* refusal is correct — a UI must not pick either branch on their behalf.
|
|
2900
|
-
*/
|
|
2901
|
-
rotateAccessLink(key: string, channelId: string, linkId: string, endActiveSessions: boolean): Promise<AccessLinkReveal & {
|
|
2902
|
-
previous: AccessLinkRecord;
|
|
2903
|
-
endedSessions: number;
|
|
2904
|
-
}>;
|
|
2905
|
-
/** Revoke. The link stops opening immediately; `endActiveSessions` decides
|
|
2906
|
-
* whether the buyers already inside keep their sessions. */
|
|
2907
|
-
revokeAccessLink(key: string, channelId: string, linkId: string, endActiveSessions?: boolean): Promise<{
|
|
2908
|
-
ok: true;
|
|
2909
|
-
link: AccessLinkRecord;
|
|
2910
|
-
endedSessions: number;
|
|
2911
|
-
}>;
|
|
2912
|
-
report(key: string): Promise<ReportResult>;
|
|
2913
|
-
controlRoom(key: string, windowMinutes?: number): Promise<ControlRoomSnapshot>;
|
|
2914
|
-
log(key: string, opts?: {
|
|
2915
|
-
limit?: number;
|
|
2916
|
-
before?: number;
|
|
2917
|
-
}): Promise<LogPage>;
|
|
2918
|
-
/** CSV report as a Blob (Bearer auth can't ride a plain <a href>). Host builds
|
|
2919
|
-
* an object URL for download. */
|
|
2920
|
-
reportCsv(key: string): Promise<Blob>;
|
|
2921
|
-
}
|
|
2922
|
-
|
|
2923
|
-
/**
|
|
2924
|
-
* SeatManager — the organizer manage surface, packaged for the SDK.
|
|
2925
|
-
*
|
|
2926
|
-
* Productizes the SeatLayer dashboard's ManageEventPage into a framework-
|
|
2927
|
-
* agnostic class (mirrors how SeatPicker productized the buyer flow). It mounts
|
|
2928
|
-
* the shared engine in `manageMode`, subscribes to the event's realtime channel
|
|
2929
|
-
* and drives three control-room tools on one persistent canvas:
|
|
2930
|
-
*
|
|
2931
|
-
* - **view** — a live board: realtime seat repaint (flash on hold/book),
|
|
2932
|
-
* live KPI tallies + gross revenue, and a streaming activity
|
|
2933
|
-
* feed derived from the delta stream + audit log. Read-only.
|
|
2934
|
-
* - **inspect** — select one seat to read its live inventory context.
|
|
2935
|
-
* - **block** — bulk-first block/unblock: marquee-drag, ⌘A select-all,
|
|
2936
|
-
* whole-category / whole-section select, single-seat fallback →
|
|
2937
|
-
* one batched block/unblock (optimistic, reconciled by the WS),
|
|
2938
|
-
* and timed auto-release.
|
|
2939
|
-
*
|
|
2940
|
-
* Auth: reads (chart/objects/WS) are public; writes/reports carry a Bearer
|
|
2941
|
-
* event-scoped manage token (`mse_…`) or a tenant secret key (`sk_…`) via
|
|
2942
|
-
* {@link ManageApi}. Box office + Sections + full Reports UI are M2/M3.
|
|
2943
|
-
*/
|
|
2944
|
-
|
|
2945
|
-
type SeatManagerMode = 'view' | 'inspect' | 'block' | 'sections' | 'channels';
|
|
2946
|
-
/**
|
|
2947
|
-
* Capabilities the cockpit's token was minted with. Channels mode is gated on
|
|
2948
|
-
* these and fails CLOSED: no `event:channels:view` ⇒ no Channels pill at all;
|
|
2949
|
-
* view without `event:channels:manage` ⇒ read-only inspection with every
|
|
2950
|
-
* mutation control absent, not merely disabled.
|
|
2951
|
-
*/
|
|
2952
|
-
type SeatManagerCapability = 'event:view' | 'event:block' | 'event:cancel' | 'event:reports' | 'event:channels:view' | 'event:channels:manage';
|
|
2953
|
-
/** DO seat status — 'blocked' has no engine analogue (→ 'not_for_sale'). */
|
|
2954
|
-
type DoStatus = 'free' | 'held' | 'booked' | 'blocked';
|
|
2955
|
-
/** Live KPI snapshot pushed to `onTallies` on every state change. */
|
|
2956
|
-
interface SeatManagerTallies {
|
|
2957
|
-
free: number;
|
|
2958
|
-
held: number;
|
|
2959
|
-
booked: number;
|
|
2960
|
-
blocked: number;
|
|
2961
|
-
/** Total seats on the chart. */
|
|
2962
|
-
total: number;
|
|
2963
|
-
/** booked / total, 0–100. */
|
|
2964
|
-
capacityPct: number;
|
|
2965
|
-
/** booked / (total − blocked), 0–100 — sell-through of sellable inventory. */
|
|
2966
|
-
sellThroughPct: number;
|
|
2967
|
-
/** Exact Σ booked unit_price snapshots from the authenticated report. */
|
|
2968
|
-
grossRevenue: number;
|
|
2969
|
-
/** Revenue is never reconstructed from chart list price. */
|
|
2970
|
-
revenueStatus: 'loading' | 'current' | 'stale';
|
|
2971
|
-
/** ISO-4217 currency for grossRevenue. */
|
|
2972
|
-
currency: string;
|
|
2973
|
-
}
|
|
2974
|
-
/** One streamed activity line for the live feed. */
|
|
2975
|
-
interface SeatManagerActivity {
|
|
2976
|
-
id: string;
|
|
2977
|
-
at: number;
|
|
2978
|
-
label: string;
|
|
2979
|
-
/** Full labels affected by this one backend/realtime operation. */
|
|
2980
|
-
labels: string[];
|
|
2981
|
-
count: number;
|
|
2982
|
-
/** Human verb: held / booked / released / blocked / unblocked. */
|
|
2983
|
-
verb: string;
|
|
2984
|
-
status: DoStatus;
|
|
2985
|
-
/** Spatial context for grouped activity when the chart defines sections. */
|
|
2986
|
-
sectionIds?: string[];
|
|
2987
|
-
sectionLabels?: string[];
|
|
2988
|
-
}
|
|
2989
|
-
/** Fired after a successful organizer action, for host toasts/telemetry. */
|
|
2990
|
-
interface SeatManagerActionResult {
|
|
2991
|
-
action: 'block' | 'unblock' | 'unblockAll' | 'cancelBooking' | 'setHoldTtl';
|
|
2992
|
-
labels: string[];
|
|
2993
|
-
count: number;
|
|
2994
|
-
}
|
|
2995
|
-
interface SeatManagerOptions {
|
|
2996
|
-
/** CSS selector or element to mount into. */
|
|
2997
|
-
container: string | HTMLElement;
|
|
2998
|
-
/** API origin. Defaults to https://api.seatlayer.io. */
|
|
2999
|
-
apiBase?: string;
|
|
3000
|
-
/** Event key (e.g. `ev_xxx` / `west-end-p3`). */
|
|
3001
|
-
eventKey: string;
|
|
3002
|
-
/** Bearer manage token — event-scoped `mse_…` or a tenant secret `sk_…`. */
|
|
3003
|
-
token: string;
|
|
3004
|
-
/** Absolute token expiry (epoch ms). Enables proactive in-place rotation. */
|
|
3005
|
-
tokenExpiresAt?: number;
|
|
3006
|
-
/** Initial mode. Default 'view'. */
|
|
3007
|
-
mode?: SeatManagerMode;
|
|
3008
|
-
/**
|
|
3009
|
-
* The capability set this token was minted with. Supply it whenever you mint
|
|
3010
|
-
* an `mse_…` grant — it is the only way the widget can know a delegated token
|
|
3011
|
-
* carries `event:channels:manage`, and without it Channels mode stays
|
|
3012
|
-
* read-only (fail-closed). A tenant secret (`sk_…`) is org authority and is
|
|
3013
|
-
* never narrowed server-side, so it is treated as fully capable.
|
|
3014
|
-
*/
|
|
3015
|
-
capabilities?: SeatManagerCapability[] | string[];
|
|
3016
|
-
/** ISO-4217 fallback currency for revenue (chart/event currency wins). */
|
|
3017
|
-
currency?: string;
|
|
3018
|
-
/** Chart theme override for the chrome (rails/bar). Chart colors come from the doc. */
|
|
3019
|
-
theme?: ChartTheme;
|
|
3020
|
-
/**
|
|
3021
|
-
* Keep the canvas painting even when the tab is hidden/backgrounded (a war-room
|
|
3022
|
-
* board on a second monitor). Calls `forceDraw()` after each delta so Chrome's
|
|
3023
|
-
* rAF throttling on occluded tabs never leaves the board stale. Default true.
|
|
3024
|
-
*/
|
|
3025
|
-
keepLiveWhileHidden?: boolean;
|
|
3026
|
-
/**
|
|
3027
|
-
* Opt in to camera-following for new buyer holds/bookings. Off by default so
|
|
3028
|
-
* a live event never steals an operator's current map context.
|
|
3029
|
-
*/
|
|
3030
|
-
followLive?: boolean;
|
|
3031
|
-
/** Chart + first snapshot are loaded and the board is live. */
|
|
3032
|
-
onReady?: () => void;
|
|
3033
|
-
/** Live KPI tallies changed. */
|
|
3034
|
-
onTallies?: (tallies: SeatManagerTallies) => void;
|
|
3035
|
-
/** A grouped live/audit activity item arrived. */
|
|
3036
|
-
onActivity?: (activity: SeatManagerActivity) => void;
|
|
3037
|
-
/** Exact private control-room projection changed. */
|
|
3038
|
-
onControlRoom?: (snapshot: ControlRoomSnapshot) => void;
|
|
3039
|
-
/** Called before token expiry. The manager swaps the result without remounting. */
|
|
3040
|
-
onTokenRefresh?: () => Promise<{
|
|
3041
|
-
token: string;
|
|
3042
|
-
expiresAt: number;
|
|
3043
|
-
}>;
|
|
3044
|
-
/** Tool/mode changed from inside the shared cockpit. */
|
|
3045
|
-
onModeChange?: (mode: SeatManagerMode) => void;
|
|
3046
|
-
/** Follow-live preference changed from inside the cockpit. */
|
|
3047
|
-
onFollowLiveChange?: (enabled: boolean) => void;
|
|
3048
|
-
/** Block-mode selection changed (marquee / ⌘A / category / section / tap). */
|
|
3049
|
-
onSelectionChange?: (seats: ExpandedSeat[]) => void;
|
|
3050
|
-
/** A block/unblock/cancel action completed successfully. */
|
|
3051
|
-
onActionComplete?: (result: SeatManagerActionResult) => void;
|
|
3052
|
-
/**
|
|
3053
|
-
* The realtime link connected or dropped, with the moment the numbers on
|
|
3054
|
-
* screen were last known good.
|
|
3055
|
-
*
|
|
3056
|
-
* A host embedding this cockpit renders its own chrome around it, and until
|
|
3057
|
-
* now had no way to know the board had gone stale: the manager tracked the
|
|
3058
|
-
* drop internally (its own LIVE/RECONNECTING pill) and told nobody. A host
|
|
3059
|
-
* that polls on a timer and pauses while the tab is hidden therefore showed
|
|
3060
|
-
* arbitrarily old numbers that looked exactly like fresh ones.
|
|
3061
|
-
*/
|
|
3062
|
-
onConnectionChange?: (state: SeatManagerConnection) => void;
|
|
3063
|
-
onError?: (err: unknown) => void;
|
|
3064
|
-
}
|
|
3065
|
-
/** Realtime link state, as reported to the embedding host. */
|
|
3066
|
-
interface SeatManagerConnection {
|
|
3067
|
-
/** `live` while the socket is open; `reconnecting` from drop until reopen. */
|
|
3068
|
-
status: 'live' | 'reconnecting';
|
|
3069
|
-
/**
|
|
3070
|
-
* `Date.now()` of the last snapshot or delta accepted from the server, or
|
|
3071
|
-
* null before the first one. This is the honest "as of" for whatever the host
|
|
3072
|
-
* is displaying — NOT the time the connection dropped, which is later and
|
|
3073
|
-
* would overstate freshness.
|
|
3074
|
-
*/
|
|
3075
|
-
lastMessageAt: number | null;
|
|
3076
|
-
}
|
|
3077
|
-
declare class SeatManager {
|
|
3078
|
-
private readonly opts;
|
|
3079
|
-
private readonly api;
|
|
3080
|
-
private readonly key;
|
|
3081
|
-
private readonly keepLive;
|
|
3082
|
-
private host;
|
|
3083
|
-
private root;
|
|
3084
|
-
private mapHost;
|
|
3085
|
-
private els;
|
|
3086
|
-
private renderer;
|
|
3087
|
-
private doc;
|
|
3088
|
-
private mode;
|
|
3089
|
-
private labelToId;
|
|
3090
|
-
private labelToSeat;
|
|
3091
|
-
private allIds;
|
|
3092
|
-
/**
|
|
3093
|
-
* GA inventory units — real sellable labels the server counts, with NO seat
|
|
3094
|
-
* geometry and therefore no renderer binding. They live here rather than in
|
|
3095
|
-
* `labelToId`/`allIds` so every paint path keeps addressing paintable nodes
|
|
3096
|
-
* only, while the tally denominator finally covers the same universe the
|
|
3097
|
-
* numerator does. Without them a GA sale hit `booked` but not `total`:
|
|
3098
|
-
* Free under-reported by GA capacity and SOLD% could exceed 100%.
|
|
3099
|
-
*/
|
|
3100
|
-
private gaUnitLabelSet;
|
|
3101
|
-
private status;
|
|
3102
|
-
/** Live non-free counters, moved by each delta rather than re-walked. */
|
|
3103
|
-
private counts;
|
|
3104
|
-
/** Bumped whenever the seat model is replaced wholesale (a full snapshot). */
|
|
3105
|
-
private modelVersion;
|
|
3106
|
-
private currency;
|
|
3107
|
-
private authoritativeGrossRevenue;
|
|
3108
|
-
private revenueStatus;
|
|
3109
|
-
private revenueRequest;
|
|
3110
|
-
private controlRoomSnapshot;
|
|
3111
|
-
/**
|
|
3112
|
-
* The server's own totals, pinned to the client model they were read against.
|
|
3113
|
-
* Display = server baseline + (client now − client then), so the authoritative
|
|
3114
|
-
* numbers land exactly on arrival and deltas still move them between reads.
|
|
3115
|
-
* A wholesale model replacement invalidates the pairing (`model`), and the
|
|
3116
|
-
* client tallies — themselves a fresh authenticated read — take over.
|
|
3117
|
-
*/
|
|
3118
|
-
private serverBaseline;
|
|
3119
|
-
/** Latest presence frame, held whether or not a snapshot has landed yet. */
|
|
3120
|
-
private livePresence;
|
|
3121
|
-
/** Latest cumulative booked gross pushed on a delta frame. */
|
|
3122
|
-
private liveGross;
|
|
3123
|
-
/** Coalesces a burst of deltas into one KPI/rail repaint. */
|
|
3124
|
-
private paintHandle;
|
|
3125
|
-
private trendWindowMinutes;
|
|
3126
|
-
private heatEnabled;
|
|
3127
|
-
private followLive;
|
|
3128
|
-
private lastKpiValues;
|
|
3129
|
-
private activeKpiDeltas;
|
|
3130
|
-
private ws;
|
|
3131
|
-
private reconnectTimer;
|
|
3132
|
-
private attempt;
|
|
3133
|
-
private closed;
|
|
3134
|
-
/** Mirrors the `live` root class, so the getter never has to read the DOM. */
|
|
3135
|
-
private connectionStatus;
|
|
3136
|
-
/** When the server last told us something. Stamped on accepted traffic only —
|
|
3137
|
-
* a socket that opens and says nothing has not refreshed anything. */
|
|
3138
|
-
private lastMessageAt;
|
|
3139
|
-
private ready;
|
|
3140
|
-
private feed;
|
|
3141
|
-
private feedTimer;
|
|
3142
|
-
private toastTimer;
|
|
3143
|
-
private liveEventTimer;
|
|
3144
|
-
private kpiCleanupTimer;
|
|
3145
|
-
private followLiveTimer;
|
|
3146
|
-
private followSeatTimer;
|
|
3147
|
-
private releaseAt;
|
|
3148
|
-
private layoutObserver;
|
|
3149
|
-
private tokenExpiresAt;
|
|
3150
|
-
private tokenRefreshTimer;
|
|
3151
|
-
private tokenRefreshInFlight;
|
|
3152
|
-
private sectionByObject;
|
|
3153
|
-
private sectionLabelById;
|
|
3154
|
-
private sectionsBase;
|
|
3155
|
-
private availabilityRules;
|
|
3156
|
-
private effectiveHidden;
|
|
3157
|
-
private effectiveClosed;
|
|
3158
|
-
private availabilitySaving;
|
|
3159
|
-
private lastSyncedAt;
|
|
3160
|
-
private blockedQuery;
|
|
3161
|
-
private blockedSection;
|
|
3162
|
-
private blockedResultLimit;
|
|
3163
|
-
private unblockAllConfirmTimer;
|
|
3164
|
-
private channels;
|
|
3165
|
-
private channelCaps;
|
|
3166
|
-
private readonly onFullscreenChange;
|
|
3167
|
-
private readonly onKeyDown;
|
|
3168
|
-
private readonly onRailClick;
|
|
3169
|
-
constructor(options: SeatManagerOptions);
|
|
3170
|
-
/** Build the DOM, load the chart, subscribe to realtime, mount the board. */
|
|
3171
|
-
render(): Promise<this>;
|
|
3172
|
-
setMode(mode: SeatManagerMode): void;
|
|
3173
|
-
/**
|
|
3174
|
-
* Decide what this token may do with sales channels.
|
|
3175
|
-
*
|
|
3176
|
-
* Declared capabilities win — a host that mints an `mse_…` grant knows exactly
|
|
3177
|
-
* what it asked for. Otherwise a tenant secret (`sk_…`) is org authority the
|
|
3178
|
-
* worker never narrows, so it is fully capable; and a delegated token with no
|
|
3179
|
-
* declaration is probed for read access and then treated as READ-ONLY, because
|
|
3180
|
-
* "we could not tell" must never render mutation controls.
|
|
3181
|
-
*/
|
|
3182
|
-
private resolveChannelCapabilities;
|
|
3183
|
-
/** The adapter between the cockpit's internals and Channels mode. */
|
|
3184
|
-
private buildChannelsHost;
|
|
3185
|
-
/** Actual on-screen seat diameter, for the channel overlay's marks. The
|
|
3186
|
-
* renderer's base seat radius is 9 chart units; retaining the camera scale
|
|
3187
|
-
* (rather than capping it) keeps every preview paint aligned with the real
|
|
3188
|
-
* chart geometry at deep zoom. */
|
|
3189
|
-
private seatPixelSize;
|
|
3190
|
-
/** Toggle the normalized sales-velocity outline overlay without changing seat colors. */
|
|
3191
|
-
setHeatOverlay(enabled: boolean): void;
|
|
3192
|
-
/** Toggle opt-in camera following for new buyer hold/book events. */
|
|
3193
|
-
setFollowLive(enabled: boolean): void;
|
|
3194
|
-
/** Change the current-vs-previous sales window and refresh the private projection. */
|
|
3195
|
-
setTrendWindow(windowMinutes: number): Promise<ControlRoomSnapshot>;
|
|
3196
|
-
enterFullscreen(): Promise<void>;
|
|
3197
|
-
exitFullscreen(): Promise<void>;
|
|
3198
|
-
isFullscreen(): boolean;
|
|
3199
|
-
private toggleFullscreen;
|
|
3200
|
-
/** Rotate the delegated credential without rebuilding DOM, canvas or socket. */
|
|
3201
|
-
setToken(token: string, expiresAt?: number): void;
|
|
3202
|
-
private scheduleTokenRefresh;
|
|
3203
|
-
private rotateToken;
|
|
3204
|
-
/** Bulk block the given labels (or the current selection when omitted). */
|
|
3205
|
-
block(labels?: string[], opts?: {
|
|
3206
|
-
releaseAt?: number;
|
|
3207
|
-
reason?: string;
|
|
3208
|
-
}): Promise<void>;
|
|
3209
|
-
unblock(labels?: string[]): Promise<void>;
|
|
3210
|
-
unblockAll(): Promise<void>;
|
|
3211
|
-
/** Cancel bookings (BOOKED → free), guarded by the original booking ref. */
|
|
3212
|
-
cancelBooking(labels: string[], bookingRef: string): Promise<void>;
|
|
3213
|
-
selectAll(): ExpandedSeat[];
|
|
3214
|
-
selectSection(sectionId: string): ExpandedSeat[];
|
|
3215
|
-
selectByLabels(labels: string[]): ExpandedSeat[];
|
|
3216
|
-
clearSelection(): void;
|
|
3217
|
-
getSelection(): ExpandedSeat[];
|
|
3218
|
-
getReport(): Promise<ReportResult>;
|
|
3219
|
-
getControlRoomSnapshot(windowMinutes?: number): Promise<ControlRoomSnapshot>;
|
|
3220
|
-
/**
|
|
3221
|
-
* The realtime link's current state and the "as of" behind it.
|
|
3222
|
-
*
|
|
3223
|
-
* Pair with `onConnectionChange` for the edges: a host that mounts after a
|
|
3224
|
-
* drop, or re-reads on tab focus, needs to be able to ASK rather than wait
|
|
3225
|
-
* for the next transition that may never come.
|
|
3226
|
-
*/
|
|
3227
|
-
getConnection(): SeatManagerConnection;
|
|
3228
|
-
getLog(opts?: {
|
|
3229
|
-
limit?: number;
|
|
3230
|
-
before?: number;
|
|
3231
|
-
}): Promise<{
|
|
3232
|
-
entries: LogEntry[];
|
|
3233
|
-
nextBefore: number | null;
|
|
3234
|
-
}>;
|
|
3235
|
-
setHoldTtl(ms: number | null): Promise<void>;
|
|
3236
|
-
/** M2 — box-office booking from free seats. Stubbed (route is session-only today). */
|
|
3237
|
-
boxBook(_labels: string[], _bookingRef: string): Promise<void>;
|
|
3238
|
-
zoomToFit(): void;
|
|
3239
|
-
destroy(): void;
|
|
3240
|
-
private buildRenderer;
|
|
3241
|
-
/** Block always uses a marquee. Channels only enables its marquee after the
|
|
3242
|
-
* organizer deliberately chooses Assign seats; Pan map keeps desktop drag
|
|
3243
|
-
* available for large charts. */
|
|
3244
|
-
private isBulkSelectMode;
|
|
3245
|
-
/**
|
|
3246
|
-
* Block never touches held or booked inventory, so it cannot select it.
|
|
3247
|
-
* Channels must be able to select it — the Review sheet's honesty depends on
|
|
3248
|
-
* counting the held and sold units inside a marquee and saying they will not
|
|
3249
|
-
* move, rather than silently omitting them from the selection.
|
|
3250
|
-
*/
|
|
3251
|
-
private selectableStatuses;
|
|
3252
|
-
private updateRendererInteraction;
|
|
3253
|
-
private handleSeatSelect;
|
|
3254
|
-
/**
|
|
3255
|
-
* Build the client's inventory universe from the chart.
|
|
3256
|
-
*
|
|
3257
|
-
* `expandChart` yields SEATS — it has no output for a GA area, whose capacity
|
|
3258
|
-
* is sold as N synthetic unit labels. The server's seat map keys, its deltas
|
|
3259
|
-
* and its `totals` all speak those labels, so a client that only knows seats
|
|
3260
|
-
* counts GA sales in the numerator (every key of the snapshot is written into
|
|
3261
|
-
* `status`) while leaving them out of the denominator. Registering the GA
|
|
3262
|
-
* units here — labels only, never a render binding — is what makes the two
|
|
3263
|
-
* agree.
|
|
3264
|
-
*/
|
|
3265
|
-
private buildUnitUniverse;
|
|
3266
|
-
/** Every sellable unit the client knows: seats + GA capacity. */
|
|
3267
|
-
private unitTotal;
|
|
3268
|
-
/** Every label the client models, whether or not it can be painted. */
|
|
3269
|
-
private knownLabels;
|
|
3270
|
-
private repaintAll;
|
|
3271
|
-
/**
|
|
3272
|
-
* Open the cockpit's realtime socket AS THE ORGANIZER.
|
|
3273
|
-
*
|
|
3274
|
-
* The scope has to be established before the upgrade, because a browser
|
|
3275
|
-
* `WebSocket` cannot send an Authorization header: the manage token is traded
|
|
3276
|
-
* over HTTPS for a one-use ticket which rides in `Sec-WebSocket-Protocol`.
|
|
3277
|
-
* Without it the server treats this socket as an anonymous public buyer and
|
|
3278
|
-
* projects its deltas, so any change inside a private channel allocation is
|
|
3279
|
-
* structurally suppressed and the map silently drifts.
|
|
3280
|
-
*
|
|
3281
|
-
* If the mint fails (an expired token, a worker that predates the route) we
|
|
3282
|
-
* still connect unticketed rather than going dark — the public-sale stream is
|
|
3283
|
-
* worth having, and every `resnapshot()` re-establishes physical truth from
|
|
3284
|
-
* the authenticated HTTP read.
|
|
3285
|
-
*/
|
|
3286
|
-
private connect;
|
|
3287
|
-
private scheduleReconnect;
|
|
3288
|
-
private onMessage;
|
|
3289
|
-
/**
|
|
3290
|
-
* Adopt the cumulative booked gross a delta frame carried.
|
|
3291
|
-
*
|
|
3292
|
-
* Stashed with its arrival time so an in-flight control-room read can decide
|
|
3293
|
-
* whether it is holding the newer number: a frame that landed after the
|
|
3294
|
-
* request started is newer than the response, one that landed before is not.
|
|
3295
|
-
*/
|
|
3296
|
-
private applyLiveGross;
|
|
3297
|
-
/** The single writer for a label's status, so the counters never drift. */
|
|
3298
|
-
private setStatusLabel;
|
|
3299
|
-
private resnapshot;
|
|
3300
|
-
/**
|
|
3301
|
-
* Replace the whole seat model.
|
|
3302
|
-
*
|
|
3303
|
-
* `fallback` is the compact frame's modal status: those snapshots list only
|
|
3304
|
-
* the seats that DIFFER from it, so every other known label takes it. Without
|
|
3305
|
-
* this the omitted majority would silently fall back to `free` — fine when
|
|
3306
|
-
* the mode really is free, wrong the moment it is not.
|
|
3307
|
-
*/
|
|
3308
|
-
private applySnapshot;
|
|
3309
|
-
/** The one O(n) walk left: a wholesale model replacement re-bases the counters. */
|
|
3310
|
-
private recountAll;
|
|
3311
|
-
/** Optimistic local write shared by organizer actions. Paint and tally once,
|
|
3312
|
-
* even when an arena-sized operation changes hundreds of seats. */
|
|
3313
|
-
private setSeatsLocal;
|
|
3314
|
-
/** Keep the canvas painting on hidden/occluded tabs (war-room second monitor). */
|
|
3315
|
-
private afterPaint;
|
|
3316
|
-
private activityColor;
|
|
3317
|
-
private sectionsForLabels;
|
|
3318
|
-
private pulseSeatLabels;
|
|
3319
|
-
/** Render one grouped realtime operation at the right semantic zoom level. */
|
|
3320
|
-
private paintSpatialActivity;
|
|
3321
|
-
private locateSection;
|
|
3322
|
-
private locateActivity;
|
|
3323
|
-
private showLiveEvent;
|
|
3324
|
-
private applyReportRevenue;
|
|
3325
|
-
/**
|
|
3326
|
-
* Read the server's own control-room projection.
|
|
3327
|
-
*
|
|
3328
|
-
* Called on mount, on every socket (re)connect and after an organizer action —
|
|
3329
|
-
* never on a timer and never per delta frame. Presence and gross that arrived
|
|
3330
|
-
* on the socket AFTER this request started are newer than the response, so
|
|
3331
|
-
* they survive it; anything older defers to the read.
|
|
3332
|
-
*/
|
|
3333
|
-
private refreshControlRoom;
|
|
3334
|
-
/** Pin the server's totals to the client model they were read against. */
|
|
3335
|
-
private rebaseServerTotals;
|
|
3336
|
-
/** What the client's own model says — GA units included since `render()`. */
|
|
3337
|
-
private clientTallies;
|
|
3338
|
-
/**
|
|
3339
|
-
* The numbers the KPI bar and rail render.
|
|
3340
|
-
*
|
|
3341
|
-
* The server is the authority: its totals land exactly as read, and the
|
|
3342
|
-
* delta-driven client model carries them forward until the next read. Before
|
|
3343
|
-
* the first snapshot — and after a wholesale model replacement invalidates the
|
|
3344
|
-
* pairing — the client model stands alone.
|
|
3345
|
-
*/
|
|
3346
|
-
private buildTallies;
|
|
3347
|
-
/**
|
|
3348
|
-
* Queue one KPI/rail repaint for this burst of changes.
|
|
3349
|
-
*
|
|
3350
|
-
* A delta frame can carry hundreds of seats and `paintKpis` rebuilds eight
|
|
3351
|
-
* nodes from scratch, so painting per change is what made an arena-sized
|
|
3352
|
-
* frame expensive. Coalescing on a frame keeps the burst to a single rebuild;
|
|
3353
|
-
* without `requestAnimationFrame` (SSR, an older test env) it paints inline
|
|
3354
|
-
* rather than dropping the update.
|
|
3355
|
-
*/
|
|
3356
|
-
private recomputeTallies;
|
|
3357
|
-
private flushTallies;
|
|
3358
|
-
private verbFor;
|
|
3359
|
-
private pushActivity;
|
|
3360
|
-
private seedFeed;
|
|
3361
|
-
private startFeedClock;
|
|
3362
|
-
private selectionLabels;
|
|
3363
|
-
private syncSelection;
|
|
3364
|
-
private buildChrome;
|
|
3365
|
-
private updateContainerLayout;
|
|
3366
|
-
private sectionOptions;
|
|
3367
|
-
private buildSectionOptions;
|
|
3368
|
-
private paintModeTabs;
|
|
3369
|
-
private paintFollowLiveButton;
|
|
3370
|
-
private paintHeatButton;
|
|
3371
|
-
private paintMomentumHelp;
|
|
3372
|
-
private paintFullscreenButton;
|
|
3373
|
-
private paintTrendWindow;
|
|
3374
|
-
private setLive;
|
|
3375
|
-
private updateZoomHint;
|
|
3376
|
-
private formatKpiDelta;
|
|
3377
|
-
private paintKpis;
|
|
3378
|
-
private paintRail;
|
|
3379
|
-
private renderViewRail;
|
|
3380
|
-
/** Live presence wins over the snapshot's copy — it is the fresher channel,
|
|
3381
|
-
* and it exists from the first frame rather than the first fetch. */
|
|
3382
|
-
private presenceCounts;
|
|
3383
|
-
private paintMonitorInsights;
|
|
3384
|
-
private applyHeatOverlay;
|
|
3385
|
-
private renderInspectRail;
|
|
3386
|
-
/** Pull the organizer's availability rules (event:view). Called on load and on
|
|
3387
|
-
* every WS (re)connect, mirroring how the other panels re-hydrate. `closed` is
|
|
3388
|
-
* deterministic from the rules; `hidden` (which folds in already-due timed /
|
|
3389
|
-
* threshold windows) comes from the snapshot + WS effective set. */
|
|
3390
|
-
private refreshAvailability;
|
|
3391
|
-
/** Run a token-authed op; on a 401 re-mint via onTokenRefresh and retry once. */
|
|
3392
|
-
private withAuthRetry;
|
|
3393
|
-
private closedIdsFromRules;
|
|
3394
|
-
/** Adopt a new effective hidden/closed set (from a snapshot or WS broadcast) and
|
|
3395
|
-
* repaint the rail + canvas when it actually moves. */
|
|
3396
|
-
private updateEffectiveAvailability;
|
|
3397
|
-
/** Canvas read of the availability state: dim hidden sections to a whisper,
|
|
3398
|
-
* half-light closed sections, leave open sections normal. Only in Sections mode;
|
|
3399
|
-
* cleared in every other tool. */
|
|
3400
|
-
private applySectionCanvasTreatment;
|
|
3401
|
-
/** Zone-grouped render tree: each zone header then its sections (which follow the
|
|
3402
|
-
* zone window), then loose sections + the ungrouped bucket. Effective hidden /
|
|
3403
|
-
* closed come from the live sets, rules from the organizer map. */
|
|
3404
|
-
private buildSectionRows;
|
|
3405
|
-
private renderSectionsRail;
|
|
3406
|
-
private sectionRowHtml;
|
|
3407
|
-
private wireSectionRail;
|
|
3408
|
-
/** Change one row's availability mode. A zone rule subsumes its child section
|
|
3409
|
-
* rules, so those are dropped from the map (the zone window is the truth). */
|
|
3410
|
-
private setSectionMode;
|
|
3411
|
-
/** Edit a timed reveal time / threshold percent on an existing row rule. */
|
|
3412
|
-
private setSectionRulePatch;
|
|
3413
|
-
/** Optimistically adopt the new rules, then reconcile with the server-cleaned
|
|
3414
|
-
* map + effective hidden/closed sets. Rolls back the rules on failure. */
|
|
3415
|
-
private persistAvailability;
|
|
3416
|
-
private paintLegend;
|
|
3417
|
-
private paintFeed;
|
|
3418
|
-
private renderBlockRail;
|
|
3419
|
-
private toggleCategory;
|
|
3420
|
-
/** A category/filter is a real toggle: add the missing seats, or remove the
|
|
3421
|
-
* whole group when every eligible seat in it is already selected. */
|
|
3422
|
-
private toggleLabels;
|
|
3423
|
-
private isBlockSelectable;
|
|
3424
|
-
private paintSelBar;
|
|
3425
|
-
private paintCategoryControls;
|
|
3426
|
-
private filteredBlockedSeats;
|
|
3427
|
-
private paintBlockedInventory;
|
|
3428
|
-
private confirmUnblockAll;
|
|
3429
|
-
private resetUnblockAllConfirm;
|
|
3430
|
-
private done;
|
|
3431
|
-
private toastOk;
|
|
3432
|
-
private toastErr;
|
|
3433
|
-
private toast;
|
|
3434
|
-
private fail;
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
2148
|
/**
|
|
3438
2149
|
* Channels mode — the sales-channel management surface inside the SeatManager
|
|
3439
2150
|
* cockpit. It ships in the SDK, so every embedding platform (and our own Control
|
|
@@ -4089,4 +2800,4 @@ declare class ChannelsMode {
|
|
|
4089
2800
|
handleBack(): boolean;
|
|
4090
2801
|
}
|
|
4091
2802
|
|
|
4092
|
-
export {
|
|
2803
|
+
export { AccessLinkReveal, AccessLinkStatusRecord, ApiError, AssignmentResult, type AttachPickerFrameOptions, type BestAvailableResult, BucketRow, BuyerAccessContext, type BuyerAccessExpiredEvent, type BuyerAccessRefreshReason, type BuyerAccessToken, type BuyerAccessTokenProvider, BuyerAccessUnavailableError, type BuyerAccessUnavailableEvent, type BuyerAccessUnavailableReason, BuyerRealtimeClient, type BuyerRealtimeOptions, ChannelAccessIntent, ChannelAllocationPage, ChannelListResult, ChannelPreviewProjection, ChannelRecord, ChannelSeatStatus, type ChannelsCapabilities, type ChannelsClient, ChannelsMode, type ChannelsModeHost, type ChannelsRowView, type ChannelsSeatView, type CheckoutHandoff, type CheckoutLineItem, type CheckoutSessionResult, EmbeddedDesigner, type EmbeddedDesignerEventType, type EmbeddedDesignerMessage, type EmbeddedDesignerOptions, type GAAreaAvailability, type HoldConflict, type HoldLineItem, type HoldResult, type OrderStatusResult, type PaymentOptionsReason, type PaymentOptionsResult, type PaymentProviderName, type Projection, type PubApiOptions, type RealtimeSink, type ResumedHoldResult, SeatPicker, type SeatPickerOptions, type SeatPickerTheme, SeatingChart, type SeatingChartOptions, type SelectedObjectUnavailableEvent, type SelectedSeat, type StatusChange, type SubscribeTicket, attachPickerFrame, bucketRowsHtml, createBuyerAccessContext, createControllerSink };
|