@seatlayer/js 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -91,7 +91,7 @@ var PubApi = class {
91
91
  };
92
92
 
93
93
  // src/SeatingChart.ts
94
- var DEFAULT_API_BASE = "https://seatmap-api.paiteq.in";
94
+ var DEFAULT_API_BASE = "https://api.seatlayer.io";
95
95
  var DEFAULT_MAX_SELECTION = 10;
96
96
  function resolveContainer(container) {
97
97
  if (typeof container === "string") {
@@ -119,15 +119,21 @@ var SeatingChart = class {
119
119
  transport: api,
120
120
  eventKey: options.event,
121
121
  maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,
122
+ currency: options.currency,
122
123
  onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),
123
- onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt }),
124
- onError: (err) => this.opts.onError?.(err)
124
+ onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats }),
125
+ onError: (err) => this.opts.onError?.(err),
126
+ onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),
127
+ onHint: (message) => this.opts.onHint?.(message),
128
+ colorblindSafe: options.colorblindSafe
125
129
  });
126
130
  }
127
131
  /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */
128
132
  async render() {
129
133
  if (this.rendered) return this;
130
134
  this.rendered = true;
135
+ await (0, import_core.loadLocale)(this.opts.locale);
136
+ if (this.opts.messages) (0, import_core.setStringOverrides)(this.opts.messages);
131
137
  this.mount = resolveContainer(this.opts.container);
132
138
  const host = document.createElement("div");
133
139
  host.style.width = "100%";
@@ -147,7 +153,7 @@ var SeatingChart = class {
147
153
  async hold() {
148
154
  try {
149
155
  const h = await this.controller.hold();
150
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt } : null;
156
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats } : null;
151
157
  } catch (err) {
152
158
  this.opts.onError?.(err);
153
159
  return null;
@@ -157,12 +163,42 @@ var SeatingChart = class {
157
163
  async bestAvailable(qty, categoryKey) {
158
164
  try {
159
165
  const h = await this.controller.bestAvailable(qty, categoryKey);
160
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels } : null;
166
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats } : null;
161
167
  } catch (err) {
162
168
  this.opts.onError?.(err);
163
169
  return null;
164
170
  }
165
171
  }
172
+ /**
173
+ * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's
174
+ * available `tiers` are on each `SelectedSeat` from `getSelection()` /
175
+ * `onSelectionChange`. Re-emits the selection with the new tier + price, and
176
+ * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`
177
+ * reverts to the default tier.
178
+ */
179
+ setSeatTier(seatId, tierId) {
180
+ this.controller.setSeatTier(seatId, tierId);
181
+ }
182
+ /**
183
+ * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts
184
+ * return one entry; empty before render()). Pair with setFloor() to build a
185
+ * host-side floor switcher.
186
+ */
187
+ getFloors() {
188
+ return this.controller.getFloors();
189
+ }
190
+ /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */
191
+ setFloor(floorId) {
192
+ if (this.controller.getFloors().length <= 1) {
193
+ console.warn("seatmap: setFloor() ignored \u2014 this chart has a single floor");
194
+ return;
195
+ }
196
+ this.controller.setFloor(floorId);
197
+ }
198
+ /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */
199
+ setColorblindSafe(on) {
200
+ this.controller.setColorblindSafe(on);
201
+ }
166
202
  /** Release the current hold (if any). No-op when nothing is held. */
167
203
  async release() {
168
204
  await this.controller.release();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/SeatingChart.ts","../src/api.ts"],"sourcesContent":["/**\n * @seatlayer/js — the framework-agnostic SeatLayer embed SDK.\n *\n * Works in any JS environment (plain HTML, React, Vue, Svelte, Angular, …).\n * Framework wrappers (@seatlayer/react, …) build on top of this.\n */\nexport { SeatingChart } from './SeatingChart';\nexport type { SeatingChartOptions, SelectedSeat } from './SeatingChart';\nexport { ApiError } from './api';\nexport type { HoldResult, HoldConflict, BestAvailableResult } from './api';\n","/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, type PickerSeat } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://seatmap-api.paiteq.in';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://seatmap-api.paiteq.in. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onError?: (err: unknown) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt }),\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const ok = await this.controller.render(host);\n if (!ok) this.rendered = false; // render() already emitted the error\n return this;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n reason: string;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://seatmap-api.paiteq.in). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, labels: string[]): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { labels },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/SeatingChart.ts","../src/api.ts"],"sourcesContent":["/**\n * @seatlayer/js — the framework-agnostic SeatLayer embed SDK.\n *\n * Works in any JS environment (plain HTML, React, Vue, Svelte, Angular, …).\n * Framework wrappers (@seatlayer/react, …) build on top of this.\n */\nexport { SeatingChart } from './SeatingChart';\nexport type { SeatingChartOptions, SelectedSeat } from './SeatingChart';\nexport { ApiError } from './api';\nexport type { HoldResult, HoldConflict, BestAvailableResult } from './api';\n","/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, loadLocale, setStringOverrides, type PickerSeat } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onError?: (err: unknown) => void;\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats }),\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const ok = await this.controller.render(host);\n if (!ok) this.rendered = false; // render() already emitted the error\n return this;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n reason: string;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, labels: string[]): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { labels },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,kBAAkF;;;ACO3E,IAAM,WAAN,cAAuB,MAAM;AAAA,EAQlC,YAAY,QAAgB,SAAiB,MAAe,WAA4B,QAAiB;AACvG,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AACF;AA4BA,eAAe,QACb,MACA,MACA,OAAoD,CAAC,GACzC;AACZ,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAkC,CAAC;AACzC,MAAI;AACJ,MAAI,KAAK,SAAS,QAAW;AAC3B,YAAQ,cAAc,IAAI;AAC1B,WAAO,KAAK,UAAU,KAAK,IAAI;AAAA,EACjC;AAEA,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,IAAI,EAAE,QAAQ,SAAS,MAAM,aAAa,OAAO,CAAC;AAExF,QAAM,UAAU,IAAI,QAAQ,IAAI,cAAc,KAAK,IAAI,SAAS,kBAAkB;AAClF,QAAM,OAAO,SAAS,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,IAAI;AAE3D,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAM;AAGZ,UAAM,IAAI,SAAS,IAAI,QAAQ,KAAK,SAAS,kBAAkB,IAAI,MAAM,IAAI,KAAK,MAAM,KAAK,WAAW,KAAK,MAAM;AAAA,EACrH;AACA,SAAO;AACT;AAGO,IAAM,SAAN,MAAa;AAAA,EAClB,YAA6B,MAAc;AAAd;AAAA,EAAe;AAAA,EAE5C,MAAM,KAAsC;AAC1C,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ;AAAA,EAC1E;AAAA,EAEA,QAAQ,KAAwC;AAC9C,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,UAAU;AAAA,EAC5E;AAAA,EAEA,KAAK,KAAa,QAAuC;AACvD,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,SAAS;AAAA,MACvE,QAAQ;AAAA,MACR,MAAM,EAAE,OAAO;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,KAAa,KAAa,aAAoD;AAC1F,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,mBAAmB;AAAA,MACjF,QAAQ;AAAA,MACR,MAAM,EAAE,KAAK,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC,EAAG;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,KAAa,QAAkB,QAAuC;AAC5E,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,YAAY;AAAA,MAC1E,QAAQ;AAAA,MACR,MAAM,EAAE,QAAQ,OAAO;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,KAAqB;AAC7B,UAAM,SAAS,KAAK,KAAK,QAAQ,SAAS,IAAI;AAC9C,WAAO,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,EACxD;AACF;;;ADhHA,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAoD9B,SAAS,iBAAiB,WAA8C;AACtE,MAAI,OAAO,cAAc,UAAU;AACjC,UAAM,KAAK,SAAS,cAAc,SAAS;AAC3C,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,uBAAuB,SAAS,aAAa;AACtE,WAAO;AAAA,EACT;AACA,MAAI,EAAE,qBAAqB,cAAc;AACvC,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,SAAO;AACT;AAEO,IAAM,eAAN,MAAmB;AAAA,EAUxB,YAAY,SAA8B;AAJ1C,SAAQ,QAA4B;AACpC,SAAQ,SAAgC;AACxC,SAAQ,WAAW;AAGjB,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,OAAM,IAAI,MAAM,qCAAqC;AAClG,QAAI,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,kCAAkC;AAC1E,QAAI,CAAC,QAAQ,SAAS,OAAO,QAAQ,UAAU,SAAU,OAAM,IAAI,MAAM,kCAAkC;AAE3G,SAAK,OAAO;AACZ,SAAK,YAAY,QAAQ;AACzB,UAAM,MAAM,IAAI,QAAQ,QAAQ,WAAW,kBAAkB,QAAQ,QAAQ,EAAE,CAAC;AAChF,SAAK,aAAa,IAAI,6BAAiB;AAAA,MACrC,WAAW;AAAA,MACX,UAAU,QAAQ;AAAA,MAClB,cAAc,QAAQ,gBAAgB;AAAA,MACtC,UAAU,QAAQ;AAAA,MAClB,mBAAmB,CAAC,UAAU,KAAK,KAAK,oBAAoB,KAAK;AAAA,MACjE,QAAQ,CAAC,MAAM,KAAK,KAAK,SAAS,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,WAAW,OAAO,EAAE,MAAM,CAAC;AAAA,MAC9F,SAAS,CAAC,QAAQ,KAAK,KAAK,UAAU,GAAG;AAAA,MACzC,WAAW,CAAC,YAAY,KAAK,KAAK,YAAY,OAAO;AAAA,MACrD,QAAQ,CAAC,YAAY,KAAK,KAAK,SAAS,OAAO;AAAA,MAC/C,gBAAgB,QAAQ;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,SAAwB;AAC5B,QAAI,KAAK,SAAU,QAAO;AAC1B,SAAK,WAAW;AAKhB,cAAM,wBAAW,KAAK,KAAK,MAAM;AACjC,QAAI,KAAK,KAAK,SAAU,qCAAmB,KAAK,KAAK,QAAQ;AAI7D,SAAK,QAAQ,iBAAiB,KAAK,KAAK,SAAS;AACjD,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,MAAM,QAAQ;AACnB,SAAK,MAAM,SAAS;AACpB,SAAK,MAAM,WAAW;AACtB,SAAK,MAAM,YAAY,IAAI;AAC3B,SAAK,SAAS;AAEd,UAAM,KAAK,MAAM,KAAK,WAAW,OAAO,IAAI;AAC5C,QAAI,CAAC,GAAI,MAAK,WAAW;AACzB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,eAA+B;AAC7B,WAAO,KAAK,WAAW,aAAa;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,OAAmC;AACvC,QAAI;AACF,YAAM,IAAI,MAAM,KAAK,WAAW,KAAK;AACrC,aAAO,IAAI,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,WAAW,OAAO,EAAE,MAAM,IAAI;AAAA,IAC5E,SAAS,KAAK;AACZ,WAAK,KAAK,UAAU,GAAG;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,KAAa,aAA2D;AAC1F,QAAI;AACF,YAAM,IAAI,MAAM,KAAK,WAAW,cAAc,KAAK,WAAW;AAC9D,aAAO,IAAI,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,WAAW,QAAQ,EAAE,QAAQ,OAAO,EAAE,MAAM,IAAI;AAAA,IAC9F,SAAS,KAAK;AACZ,WAAK,KAAK,UAAU,GAAG;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,QAAgB,QAA6B;AACvD,SAAK,WAAW,YAAY,QAAQ,MAAM;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAA4C;AAC1C,WAAO,KAAK,WAAW,UAAU;AAAA,EACnC;AAAA;AAAA,EAGA,SAAS,SAAuB;AAC9B,QAAI,KAAK,WAAW,UAAU,EAAE,UAAU,GAAG;AAC3C,cAAQ,KAAK,kEAA6D;AAC1E;AAAA,IACF;AACA,SAAK,WAAW,SAAS,OAAO;AAAA,EAClC;AAAA;AAAA,EAGA,kBAAkB,IAAmB;AACnC,SAAK,WAAW,kBAAkB,EAAE;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,KAAK,WAAW,QAAQ;AAAA,EAChC;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,WAAW,QAAQ;AACxB,QAAI,KAAK,UAAU,KAAK,OAAO,WAAY,MAAK,OAAO,WAAW,YAAY,KAAK,MAAM;AACzF,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AACF;","names":[]}
package/dist/index.d.cts CHANGED
@@ -26,12 +26,15 @@ declare class ApiError extends Error {
26
26
  interface HoldResult {
27
27
  holdId: string;
28
28
  expiresAt: number;
29
+ /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */
30
+ seats?: PickerSeat[];
29
31
  }
30
32
  /** Best-available response — the server-picked seats plus the hold they landed in. */
31
33
  interface BestAvailableResult {
32
34
  holdId: string;
33
35
  expiresAt: number;
34
36
  labels: string[];
37
+ seats?: PickerSeat[];
35
38
  }
36
39
 
37
40
  /**
@@ -51,15 +54,46 @@ interface SeatingChartOptions {
51
54
  container: string | HTMLElement;
52
55
  /** Event key, e.g. `ev_xxx`. */
53
56
  event: string;
54
- /** API origin. Defaults to https://seatmap-api.paiteq.in. */
57
+ /** API origin. Defaults to https://api.seatlayer.io. */
55
58
  apiBase?: string;
56
59
  /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */
57
60
  publicKey?: string;
58
61
  /** Max seats selectable at once (default 10). */
59
62
  maxSelection?: number;
63
+ /**
64
+ * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to
65
+ * the browser language, then English. Built-in: en, es, de, fr. The German
66
+ * bundle (etc.) is fetched on demand so unused languages cost nothing.
67
+ */
68
+ locale?: string;
69
+ /**
70
+ * Per-key string overrides layered over the active locale — white-label copy
71
+ * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.
72
+ */
73
+ messages?: Record<string, string>;
74
+ /** ISO 4217 currency for on-map prices (default USD). */
75
+ currency?: string;
76
+ /**
77
+ * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette
78
+ * and booked seats render hollow, so state never relies on hue alone.
79
+ * Toggleable later with setColorblindSafe().
80
+ */
81
+ colorblindSafe?: boolean;
60
82
  onSelectionChange?: (seats: SelectedSeat[]) => void;
61
83
  onHold?: (result: HoldResult) => void;
62
84
  onError?: (err: unknown) => void;
85
+ /**
86
+ * Multi-floor charts only: fires when the buyer taps a deck in the stacked
87
+ * 3D view, after the picker switches to that floor — lets the host page sync
88
+ * its own floor UI (tabs, labels) with the map.
89
+ */
90
+ onDeckTap?: (floorId: string) => void;
91
+ /**
92
+ * Non-blocking, localized selection advice — currently the orphan-seat hint
93
+ * (the selection would strand a single free seat between taken neighbors).
94
+ * `null` clears it. Purely informational; nothing is ever prevented.
95
+ */
96
+ onHint?: (message: string | null) => void;
63
97
  }
64
98
  declare class SeatingChart {
65
99
  private readonly opts;
@@ -78,6 +112,27 @@ declare class SeatingChart {
78
112
  hold(): Promise<HoldResult | null>;
79
113
  /** Ask the server for the `qty` best free seats and hold them atomically. */
80
114
  bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null>;
115
+ /**
116
+ * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's
117
+ * available `tiers` are on each `SelectedSeat` from `getSelection()` /
118
+ * `onSelectionChange`. Re-emits the selection with the new tier + price, and
119
+ * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`
120
+ * reverts to the default tier.
121
+ */
122
+ setSeatTier(seatId: string, tierId: string | null): void;
123
+ /**
124
+ * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts
125
+ * return one entry; empty before render()). Pair with setFloor() to build a
126
+ * host-side floor switcher.
127
+ */
128
+ getFloors(): {
129
+ id: string;
130
+ name: string;
131
+ }[];
132
+ /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */
133
+ setFloor(floorId: string): void;
134
+ /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */
135
+ setColorblindSafe(on: boolean): void;
81
136
  /** Release the current hold (if any). No-op when nothing is held. */
82
137
  release(): Promise<void>;
83
138
  /** Tear everything down: close the socket, stop timers, drop the canvas. */
package/dist/index.d.ts CHANGED
@@ -26,12 +26,15 @@ declare class ApiError extends Error {
26
26
  interface HoldResult {
27
27
  holdId: string;
28
28
  expiresAt: number;
29
+ /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */
30
+ seats?: PickerSeat[];
29
31
  }
30
32
  /** Best-available response — the server-picked seats plus the hold they landed in. */
31
33
  interface BestAvailableResult {
32
34
  holdId: string;
33
35
  expiresAt: number;
34
36
  labels: string[];
37
+ seats?: PickerSeat[];
35
38
  }
36
39
 
37
40
  /**
@@ -51,15 +54,46 @@ interface SeatingChartOptions {
51
54
  container: string | HTMLElement;
52
55
  /** Event key, e.g. `ev_xxx`. */
53
56
  event: string;
54
- /** API origin. Defaults to https://seatmap-api.paiteq.in. */
57
+ /** API origin. Defaults to https://api.seatlayer.io. */
55
58
  apiBase?: string;
56
59
  /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */
57
60
  publicKey?: string;
58
61
  /** Max seats selectable at once (default 10). */
59
62
  maxSelection?: number;
63
+ /**
64
+ * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to
65
+ * the browser language, then English. Built-in: en, es, de, fr. The German
66
+ * bundle (etc.) is fetched on demand so unused languages cost nothing.
67
+ */
68
+ locale?: string;
69
+ /**
70
+ * Per-key string overrides layered over the active locale — white-label copy
71
+ * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.
72
+ */
73
+ messages?: Record<string, string>;
74
+ /** ISO 4217 currency for on-map prices (default USD). */
75
+ currency?: string;
76
+ /**
77
+ * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette
78
+ * and booked seats render hollow, so state never relies on hue alone.
79
+ * Toggleable later with setColorblindSafe().
80
+ */
81
+ colorblindSafe?: boolean;
60
82
  onSelectionChange?: (seats: SelectedSeat[]) => void;
61
83
  onHold?: (result: HoldResult) => void;
62
84
  onError?: (err: unknown) => void;
85
+ /**
86
+ * Multi-floor charts only: fires when the buyer taps a deck in the stacked
87
+ * 3D view, after the picker switches to that floor — lets the host page sync
88
+ * its own floor UI (tabs, labels) with the map.
89
+ */
90
+ onDeckTap?: (floorId: string) => void;
91
+ /**
92
+ * Non-blocking, localized selection advice — currently the orphan-seat hint
93
+ * (the selection would strand a single free seat between taken neighbors).
94
+ * `null` clears it. Purely informational; nothing is ever prevented.
95
+ */
96
+ onHint?: (message: string | null) => void;
63
97
  }
64
98
  declare class SeatingChart {
65
99
  private readonly opts;
@@ -78,6 +112,27 @@ declare class SeatingChart {
78
112
  hold(): Promise<HoldResult | null>;
79
113
  /** Ask the server for the `qty` best free seats and hold them atomically. */
80
114
  bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null>;
115
+ /**
116
+ * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's
117
+ * available `tiers` are on each `SelectedSeat` from `getSelection()` /
118
+ * `onSelectionChange`. Re-emits the selection with the new tier + price, and
119
+ * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`
120
+ * reverts to the default tier.
121
+ */
122
+ setSeatTier(seatId: string, tierId: string | null): void;
123
+ /**
124
+ * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts
125
+ * return one entry; empty before render()). Pair with setFloor() to build a
126
+ * host-side floor switcher.
127
+ */
128
+ getFloors(): {
129
+ id: string;
130
+ name: string;
131
+ }[];
132
+ /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */
133
+ setFloor(floorId: string): void;
134
+ /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */
135
+ setColorblindSafe(on: boolean): void;
81
136
  /** Release the current hold (if any). No-op when nothing is held. */
82
137
  release(): Promise<void>;
83
138
  /** Tear everything down: close the socket, stop timers, drop the canvas. */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/SeatingChart.ts
2
- import { PickerController } from "@seatlayer/core";
2
+ import { PickerController, loadLocale, setStringOverrides } from "@seatlayer/core";
3
3
 
4
4
  // src/api.ts
5
5
  var ApiError = class extends Error {
@@ -64,7 +64,7 @@ var PubApi = class {
64
64
  };
65
65
 
66
66
  // src/SeatingChart.ts
67
- var DEFAULT_API_BASE = "https://seatmap-api.paiteq.in";
67
+ var DEFAULT_API_BASE = "https://api.seatlayer.io";
68
68
  var DEFAULT_MAX_SELECTION = 10;
69
69
  function resolveContainer(container) {
70
70
  if (typeof container === "string") {
@@ -92,15 +92,21 @@ var SeatingChart = class {
92
92
  transport: api,
93
93
  eventKey: options.event,
94
94
  maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,
95
+ currency: options.currency,
95
96
  onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),
96
- onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt }),
97
- onError: (err) => this.opts.onError?.(err)
97
+ onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats }),
98
+ onError: (err) => this.opts.onError?.(err),
99
+ onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),
100
+ onHint: (message) => this.opts.onHint?.(message),
101
+ colorblindSafe: options.colorblindSafe
98
102
  });
99
103
  }
100
104
  /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */
101
105
  async render() {
102
106
  if (this.rendered) return this;
103
107
  this.rendered = true;
108
+ await loadLocale(this.opts.locale);
109
+ if (this.opts.messages) setStringOverrides(this.opts.messages);
104
110
  this.mount = resolveContainer(this.opts.container);
105
111
  const host = document.createElement("div");
106
112
  host.style.width = "100%";
@@ -120,7 +126,7 @@ var SeatingChart = class {
120
126
  async hold() {
121
127
  try {
122
128
  const h = await this.controller.hold();
123
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt } : null;
129
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats } : null;
124
130
  } catch (err) {
125
131
  this.opts.onError?.(err);
126
132
  return null;
@@ -130,12 +136,42 @@ var SeatingChart = class {
130
136
  async bestAvailable(qty, categoryKey) {
131
137
  try {
132
138
  const h = await this.controller.bestAvailable(qty, categoryKey);
133
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels } : null;
139
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats } : null;
134
140
  } catch (err) {
135
141
  this.opts.onError?.(err);
136
142
  return null;
137
143
  }
138
144
  }
145
+ /**
146
+ * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's
147
+ * available `tiers` are on each `SelectedSeat` from `getSelection()` /
148
+ * `onSelectionChange`. Re-emits the selection with the new tier + price, and
149
+ * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`
150
+ * reverts to the default tier.
151
+ */
152
+ setSeatTier(seatId, tierId) {
153
+ this.controller.setSeatTier(seatId, tierId);
154
+ }
155
+ /**
156
+ * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts
157
+ * return one entry; empty before render()). Pair with setFloor() to build a
158
+ * host-side floor switcher.
159
+ */
160
+ getFloors() {
161
+ return this.controller.getFloors();
162
+ }
163
+ /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */
164
+ setFloor(floorId) {
165
+ if (this.controller.getFloors().length <= 1) {
166
+ console.warn("seatmap: setFloor() ignored \u2014 this chart has a single floor");
167
+ return;
168
+ }
169
+ this.controller.setFloor(floorId);
170
+ }
171
+ /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */
172
+ setColorblindSafe(on) {
173
+ this.controller.setColorblindSafe(on);
174
+ }
139
175
  /** Release the current hold (if any). No-op when nothing is held. */
140
176
  async release() {
141
177
  await this.controller.release();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SeatingChart.ts","../src/api.ts"],"sourcesContent":["/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, type PickerSeat } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://seatmap-api.paiteq.in';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://seatmap-api.paiteq.in. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onError?: (err: unknown) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt }),\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const ok = await this.controller.render(host);\n if (!ok) this.rendered = false; // render() already emitted the error\n return this;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n reason: string;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://seatmap-api.paiteq.in). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, labels: string[]): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { labels },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n"],"mappings":";AASA,SAAS,wBAAyC;;;ACO3C,IAAM,WAAN,cAAuB,MAAM;AAAA,EAQlC,YAAY,QAAgB,SAAiB,MAAe,WAA4B,QAAiB;AACvG,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AACF;AAyBA,eAAe,QACb,MACA,MACA,OAAoD,CAAC,GACzC;AACZ,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAkC,CAAC;AACzC,MAAI;AACJ,MAAI,KAAK,SAAS,QAAW;AAC3B,YAAQ,cAAc,IAAI;AAC1B,WAAO,KAAK,UAAU,KAAK,IAAI;AAAA,EACjC;AAEA,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,IAAI,EAAE,QAAQ,SAAS,MAAM,aAAa,OAAO,CAAC;AAExF,QAAM,UAAU,IAAI,QAAQ,IAAI,cAAc,KAAK,IAAI,SAAS,kBAAkB;AAClF,QAAM,OAAO,SAAS,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,IAAI;AAE3D,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAM;AAGZ,UAAM,IAAI,SAAS,IAAI,QAAQ,KAAK,SAAS,kBAAkB,IAAI,MAAM,IAAI,KAAK,MAAM,KAAK,WAAW,KAAK,MAAM;AAAA,EACrH;AACA,SAAO;AACT;AAGO,IAAM,SAAN,MAAa;AAAA,EAClB,YAA6B,MAAc;AAAd;AAAA,EAAe;AAAA,EAE5C,MAAM,KAAsC;AAC1C,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ;AAAA,EAC1E;AAAA,EAEA,QAAQ,KAAwC;AAC9C,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,UAAU;AAAA,EAC5E;AAAA,EAEA,KAAK,KAAa,QAAuC;AACvD,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,SAAS;AAAA,MACvE,QAAQ;AAAA,MACR,MAAM,EAAE,OAAO;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,KAAa,KAAa,aAAoD;AAC1F,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,mBAAmB;AAAA,MACjF,QAAQ;AAAA,MACR,MAAM,EAAE,KAAK,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC,EAAG;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,KAAa,QAAkB,QAAuC;AAC5E,WAAO,QAAQ,KAAK,MAAM,eAAe,mBAAmB,GAAG,CAAC,YAAY;AAAA,MAC1E,QAAQ;AAAA,MACR,MAAM,EAAE,QAAQ,OAAO;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,KAAqB;AAC7B,UAAM,SAAS,KAAK,KAAK,QAAQ,SAAS,IAAI;AAC9C,WAAO,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,EACxD;AACF;;;AD7GA,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAqB9B,SAAS,iBAAiB,WAA8C;AACtE,MAAI,OAAO,cAAc,UAAU;AACjC,UAAM,KAAK,SAAS,cAAc,SAAS;AAC3C,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,uBAAuB,SAAS,aAAa;AACtE,WAAO;AAAA,EACT;AACA,MAAI,EAAE,qBAAqB,cAAc;AACvC,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,SAAO;AACT;AAEO,IAAM,eAAN,MAAmB;AAAA,EAUxB,YAAY,SAA8B;AAJ1C,SAAQ,QAA4B;AACpC,SAAQ,SAAgC;AACxC,SAAQ,WAAW;AAGjB,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,OAAM,IAAI,MAAM,qCAAqC;AAClG,QAAI,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,kCAAkC;AAC1E,QAAI,CAAC,QAAQ,SAAS,OAAO,QAAQ,UAAU,SAAU,OAAM,IAAI,MAAM,kCAAkC;AAE3G,SAAK,OAAO;AACZ,SAAK,YAAY,QAAQ;AACzB,UAAM,MAAM,IAAI,QAAQ,QAAQ,WAAW,kBAAkB,QAAQ,QAAQ,EAAE,CAAC;AAChF,SAAK,aAAa,IAAI,iBAAiB;AAAA,MACrC,WAAW;AAAA,MACX,UAAU,QAAQ;AAAA,MAClB,cAAc,QAAQ,gBAAgB;AAAA,MACtC,mBAAmB,CAAC,UAAU,KAAK,KAAK,oBAAoB,KAAK;AAAA,MACjE,QAAQ,CAAC,MAAM,KAAK,KAAK,SAAS,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,UAAU,CAAC;AAAA,MAC9E,SAAS,CAAC,QAAQ,KAAK,KAAK,UAAU,GAAG;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,SAAwB;AAC5B,QAAI,KAAK,SAAU,QAAO;AAC1B,SAAK,WAAW;AAIhB,SAAK,QAAQ,iBAAiB,KAAK,KAAK,SAAS;AACjD,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,MAAM,QAAQ;AACnB,SAAK,MAAM,SAAS;AACpB,SAAK,MAAM,WAAW;AACtB,SAAK,MAAM,YAAY,IAAI;AAC3B,SAAK,SAAS;AAEd,UAAM,KAAK,MAAM,KAAK,WAAW,OAAO,IAAI;AAC5C,QAAI,CAAC,GAAI,MAAK,WAAW;AACzB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,eAA+B;AAC7B,WAAO,KAAK,WAAW,aAAa;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,OAAmC;AACvC,QAAI;AACF,YAAM,IAAI,MAAM,KAAK,WAAW,KAAK;AACrC,aAAO,IAAI,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,UAAU,IAAI;AAAA,IAC5D,SAAS,KAAK;AACZ,WAAK,KAAK,UAAU,GAAG;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,KAAa,aAA2D;AAC1F,QAAI;AACF,YAAM,IAAI,MAAM,KAAK,WAAW,cAAc,KAAK,WAAW;AAC9D,aAAO,IAAI,EAAE,QAAQ,EAAE,QAAQ,WAAW,EAAE,WAAW,QAAQ,EAAE,OAAO,IAAI;AAAA,IAC9E,SAAS,KAAK;AACZ,WAAK,KAAK,UAAU,GAAG;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,KAAK,WAAW,QAAQ;AAAA,EAChC;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,WAAW,QAAQ;AACxB,QAAI,KAAK,UAAU,KAAK,OAAO,WAAY,MAAK,OAAO,WAAW,YAAY,KAAK,MAAM;AACzF,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/SeatingChart.ts","../src/api.ts"],"sourcesContent":["/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, loadLocale, setStringOverrides, type PickerSeat } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onError?: (err: unknown) => void;\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats }),\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const ok = await this.controller.render(host);\n if (!ok) this.rendered = false; // render() already emitted the error\n return this;\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold();\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n reason: string;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, labels: string[]): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { labels },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seatlayer/js",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "The SeatLayer embed SDK — render an interactive seat picker and hold seats from the browser. Works in any JS framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.seatlayer.io",
@@ -35,7 +35,7 @@
35
35
  "reserved-seating"
36
36
  ],
37
37
  "dependencies": {
38
- "@seatlayer/core": "^0.1.2"
38
+ "@seatlayer/core": "^0.1.4"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsup": "^8.5.1",