@seatlayer/js 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -58,7 +58,13 @@ async function request(base, path, init = {}) {
58
58
  const data = isJson ? await res.json().catch(() => null) : null;
59
59
  if (!res.ok) {
60
60
  const err = data;
61
- throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);
61
+ throw new ApiError(
62
+ res.status,
63
+ err?.error ?? `request_failed_${res.status}`,
64
+ err?.code ?? err?.error,
65
+ err?.conflicts,
66
+ err?.reason
67
+ );
62
68
  }
63
69
  return data;
64
70
  }
@@ -131,6 +137,7 @@ var SeatingChart = class {
131
137
  this.mount = null;
132
138
  this.hostEl = null;
133
139
  this.rendered = false;
140
+ this.mode_ = null;
134
141
  this.tipEl = null;
135
142
  this.tipPos = { x: 0, y: 0 };
136
143
  this.onTipMove = null;
@@ -184,6 +191,7 @@ var SeatingChart = class {
184
191
  this.rendered = false;
185
192
  return this;
186
193
  }
194
+ this.mode_ = info.mode === "test" ? "test" : "live";
187
195
  if (this.opts.seatTooltip !== false) {
188
196
  const tip = document.createElement("div");
189
197
  tip.setAttribute("role", "tooltip");
@@ -257,6 +265,19 @@ var SeatingChart = class {
257
265
  this.tipEl.style.display = "block";
258
266
  this.placeTooltip();
259
267
  }
268
+ /**
269
+ * Whether the SERVED event is a live or a test event (`sk_test_` keys create
270
+ * test events, which never book real inventory). `null` before render()
271
+ * resolves — the mode comes from the server with the chart, not from options.
272
+ *
273
+ * The widget already surfaces this visually with the test-mode ribbon; this
274
+ * getter is for hosts that draw their own chrome — notably a native WebView
275
+ * wrapper, which must be able to tell an integrator that the build they are
276
+ * about to ship is pointed at a test event.
277
+ */
278
+ getMode() {
279
+ return this.mode_;
280
+ }
260
281
  /** Current selection with prices resolved from the chart categories. */
261
282
  getSelection() {
262
283
  return this.controller.getSelection();
@@ -264,17 +285,49 @@ var SeatingChart = class {
264
285
  /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */
265
286
  async hold(options = {}) {
266
287
  try {
267
- const h = await this.controller.hold(void 0, options.ttlMs);
268
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
288
+ return await this.holdOrThrow(options);
269
289
  } catch (err) {
270
290
  this.opts.onError?.(err);
271
291
  return null;
272
292
  }
273
293
  }
294
+ /**
295
+ * @internal Like {@link hold} but RE-THROWS the structured API error (409
296
+ * `reason`/`code` + `conflicts`) instead of swallowing it into `onError` +
297
+ * `null`. The native WebView host adapter needs the throw so it can answer the
298
+ * originating command with a correlated error carrying the SPECIFIC reason
299
+ * (`sold_out` vs `not_enough_together`); the public method above keeps the
300
+ * catch-and-onError contract that direct web consumers rely on. Not a stable
301
+ * part of the embed API.
302
+ */
303
+ async holdOrThrow(options = {}) {
304
+ const h = await this.controller.hold(void 0, options.ttlMs);
305
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
306
+ }
274
307
  /** Restore an active hold by its opaque id without extending its expiry. */
275
308
  async resumeHold(holdId) {
276
309
  try {
277
- const h = await this.controller.resumeHold(holdId);
310
+ return await this.resumeHoldOrThrow(holdId);
311
+ } catch (err) {
312
+ this.opts.onError?.(err);
313
+ return null;
314
+ }
315
+ }
316
+ /** @internal Throwing variant of {@link resumeHold} for the native host adapter. See {@link holdOrThrow}. */
317
+ async resumeHoldOrThrow(holdId) {
318
+ const h = await this.controller.resumeHold(holdId);
319
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
320
+ }
321
+ /**
322
+ * Push the OPEN hold's expiry out ("need more time?"). Resolves the refreshed
323
+ * hold, or `null` when there is nothing held or the server refused (the hold
324
+ * is gone, already expired, or at its renewal cap) — refusal is a normal
325
+ * outcome, not an error, so the host decides the copy. The client-side expiry
326
+ * timer is re-armed to match, so `onHoldExpired` won't fire early.
327
+ */
328
+ async extendHold(ttlMs) {
329
+ try {
330
+ const h = await this.controller.extendHold(ttlMs);
278
331
  return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
279
332
  } catch (err) {
280
333
  this.opts.onError?.(err);
@@ -291,23 +344,31 @@ var SeatingChart = class {
291
344
  }
292
345
  async holdGA(areaId, qty, options = {}) {
293
346
  try {
294
- const h = await this.controller.holdGA(areaId, qty, options);
295
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
347
+ return await this.holdGAOrThrow(areaId, qty, options);
296
348
  } catch (err) {
297
349
  this.opts.onError?.(err);
298
350
  return null;
299
351
  }
300
352
  }
353
+ /** @internal Throwing variant of {@link holdGA} for the native host adapter. See {@link holdOrThrow}. */
354
+ async holdGAOrThrow(areaId, qty, options = {}) {
355
+ const h = await this.controller.holdGA(areaId, qty, options);
356
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;
357
+ }
301
358
  /** Ask the server for the `qty` best free seats and hold them atomically. */
302
359
  async bestAvailable(qty, categoryKey) {
303
360
  try {
304
- const h = await this.controller.bestAvailable(qty, categoryKey);
305
- return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats, items: h.items } : null;
361
+ return await this.bestAvailableOrThrow(qty, categoryKey);
306
362
  } catch (err) {
307
363
  this.opts.onError?.(err);
308
364
  return null;
309
365
  }
310
366
  }
367
+ /** @internal Throwing variant of {@link bestAvailable} for the native host adapter. See {@link holdOrThrow}. */
368
+ async bestAvailableOrThrow(qty, categoryKey) {
369
+ const h = await this.controller.bestAvailable(qty, categoryKey);
370
+ return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats, items: h.items } : null;
371
+ }
311
372
  /**
312
373
  * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's
313
374
  * available `tiers` are on each `SelectedSeat` from `getSelection()` /
@@ -368,6 +429,7 @@ var SeatingChart = class {
368
429
  this.hostEl = null;
369
430
  this.mount = null;
370
431
  this.rendered = false;
432
+ this.mode_ = null;
371
433
  }
372
434
  };
373
435