@seatlayer/js 0.67.14 → 0.68.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/README.md CHANGED
@@ -1,20 +1,46 @@
1
- # @seatlayer/js
1
+ # SeatLayer JavaScript Seat Map SDK for Reserved Seating
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@seatlayer/js)](https://www.npmjs.com/package/@seatlayer/js)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@seatlayer/js)](https://www.npmjs.com/package/@seatlayer/js)
5
-
6
- The framework-agnostic SeatLayer embed SDK. Render the complete buyer picker or
7
- a headless interactive chart, let buyers select and **hold** inventory in the
8
- browser, then **book** it from your trusted server.
9
-
10
- [Package on npm](https://www.npmjs.com/package/@seatlayer/js) ·
11
- [Install guide](https://docs.seatlayer.io/buyer-sdk/install/) ·
12
- [Live demo](https://app.seatlayer.io/demo/play) ·
13
- [Website](https://seatlayer.io/developers/) ·
14
- [AI Toolkit](https://github.com/seatlayer/seatlayer-ai-toolkit)
15
-
16
- Works in plain HTML and any framework (React, Vue, Svelte, Angular…). For React,
17
- prefer the [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react) wrapper.
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-types%20included-3178C6.svg)](https://www.typescriptlang.org/)
6
+
7
+ The framework-agnostic SeatLayer seat map SDK for the browser. Render an
8
+ interactive seating chart or a complete seat picker, show live seat
9
+ availability, and let buyers take temporary holds on the inventory they choose.
10
+
11
+ The browser **selects and holds**; your trusted server **books**. It works in
12
+ plain HTML and in any framework.
13
+
14
+ [SeatLayer JavaScript SDK on npm](https://www.npmjs.com/package/@seatlayer/js) ·
15
+ [Buyer SDK installation guide](https://docs.seatlayer.io/buyer-sdk/install/) ·
16
+ [SeatLayer reserved-seating platform](https://seatlayer.io/) ·
17
+ [Buyer seat-map demo](https://app.seatlayer.io/demo/play/grand-theatre) ·
18
+ [SeatLayer React seat map SDK](https://www.npmjs.com/package/@seatlayer/react) ·
19
+ [SeatLayer Vue seat map SDK](https://www.npmjs.com/package/@seatlayer/vue) ·
20
+ [SeatLayer Angular seat map SDK](https://www.npmjs.com/package/@seatlayer/angular) ·
21
+ [SeatLayer AI Toolkit](https://github.com/seatlayer/seatlayer-ai-toolkit)
22
+
23
+ For React, Vue, or Angular, prefer the first-party wrapper — it is this same
24
+ runtime with the framework's own component, props, and lifecycle around it.
25
+
26
+ ## What is included
27
+
28
+ - `SeatingChart` — the headless interactive chart, mounted into an element you
29
+ own.
30
+ - `SeatPicker` — the complete buyer experience: map, legend, priced tray, hold
31
+ timer, and the checkout hand-off.
32
+ - `EmbeddedDesigner` — a hosted chart Designer inside your own application.
33
+ - `SeatManager` and `ManageApi`, from the `@seatlayer/js/manager` subpath — the
34
+ organizer control room and event-scoped inventory client.
35
+ - `attachPickerFrame` — the host-side iframe helper for embedded pickers.
36
+ - TypeScript declarations for ESM (`dist/index.d.ts`) and CommonJS
37
+ (`dist/index.d.cts`), for the root and the `./manager` subpath.
38
+
39
+ ## Requirements
40
+
41
+ - A browser DOM. Give the container a definite height; the chart sizes itself
42
+ to its container, not to the viewport.
43
+ - No framework, build step, or peer dependency is required.
18
44
 
19
45
  ## Install
20
46
 
@@ -22,7 +48,19 @@ prefer the [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react)
22
48
  npm install @seatlayer/js
23
49
  ```
24
50
 
25
- ## Usage
51
+ No build tool? Load the hosted bundle instead — it exposes a `seatlayer`
52
+ global. Pin an exact version in production; the major alias always redirects to
53
+ the newest release in that line.
54
+
55
+ ```html
56
+ <div id="picker" style="width: 100%; height: 640px"></div>
57
+ <script src="https://cdn.seatlayer.io/seatlayer-js@0/seatlayer.js"></script>
58
+ <script>
59
+ new seatlayer.SeatPicker({ container: '#picker', event: 'ev_9f3a' }).render();
60
+ </script>
61
+ ```
62
+
63
+ ## Quick start
26
64
 
27
65
  ```js
28
66
  import { SeatingChart } from '@seatlayer/js';
@@ -30,6 +68,7 @@ import { SeatingChart } from '@seatlayer/js';
30
68
  const chart = new SeatingChart({
31
69
  container: '#chart',
32
70
  event: 'ev_9f3a',
71
+ publicKey: 'pk_test_…',
33
72
  onHold: ({ holdId }) => bookOnYourServer(holdId),
34
73
  });
35
74
 
@@ -39,6 +78,61 @@ const hold = await chart.hold(); // null on a 409 conflict
39
78
  chart.destroy();
40
79
  ```
41
80
 
81
+ For an ordinary Public sale on a Platform/SDK event, `publicKey` starts one
82
+ direct bootstrap after SeatLayer validates the key, event mode, and browser's
83
+ exact registered origin. The SDK keeps the returned Public-only bearer in
84
+ memory, and the bootstrap carries the chart plus compact inventory status
85
+ together. Login, presale, partner, and channel inventory instead use
86
+ `buyerAccessTokenProvider` or `buyerAccessToken` from your authenticated
87
+ backend; either explicit credential takes precedence over `publicKey`. Managed
88
+ public/unlisted events retain anonymous event-key access and omit `publicKey`.
89
+
90
+ ## Fixed Renewable Season (private-beta candidate)
91
+
92
+ The Season source is merged for development, but it is not included in the
93
+ currently registered stable package. The validated out-of-band candidate is
94
+ `0.67.0-season-s08.0`; the npm badge and install command above describe the
95
+ stable registered package and do not prove this candidate is published.
96
+
97
+ `SeasonPicker` is a distinct fixed-inclusion surface. Your server mints a
98
+ short-lived `bss_` session for the browser's exact Origin; keep that token in
99
+ memory. The picker returns an opaque, price-free handoff with the immutable Plan
100
+ activation, stable operation/hold identities, expiry/policy, and per-occurrence
101
+ outcomes. Inspect and book it from trusted server code.
102
+
103
+ ```js
104
+ import { SeasonPicker } from '@seatlayer/js';
105
+
106
+ const picker = new SeasonPicker({
107
+ container: '#season',
108
+ season: 'sea_2027',
109
+ buyerAccessToken: session.token,
110
+ onContinue: (handoff) => continueOnYourServer(handoff.operationId),
111
+ });
112
+ await picker.render();
113
+ await picker.holdSameSeat(['A-1'], 'sop_checkout_1183');
114
+
115
+ // Caller-stable and exact-replayable. Do not invent a new id after uncertainty.
116
+ await picker.release('sra_checkout_1183');
117
+
118
+ // Returning-holder journey: this records browser intent only. It never proves
119
+ // price, payment, an order, or a renewed Contract; your trusted backend must
120
+ // inspect and commit the exact offer with a caller-stable action ID.
121
+ const intent = await picker.createRenewalIntent('sro_returning_holder_1183');
122
+ sendIntentToYourBackend(intent);
123
+ ```
124
+
125
+ Supply `initialOperationId` to restore a lost create response. Pending operations
126
+ are polled through their retained operation URL; `partial_terminal` stays visible
127
+ and must be reconciled rather than replaced with a blind new action. This is an
128
+ unpublished private-beta candidate, not the currently registered npm package.
129
+
130
+ The private-beta claim is this framework-agnostic JavaScript `SeasonPicker`
131
+ only. `@seatlayer/react`, `@seatlayer/vue`, `@seatlayer/angular`, React Native,
132
+ Flutter, iOS, and Android do not expose a verified Season wrapper and are
133
+ explicitly unsupported for this candidate. A host may mount this plain-JS
134
+ surface inside a framework, but that does not create a wrapper support claim.
135
+
42
136
  ## Use in any framework
43
137
 
44
138
  The SDK only needs a DOM element and mount/unmount hooks:
@@ -51,6 +145,27 @@ onUnmounted(() => chart?.destroy());
51
145
 
52
146
  Svelte → `onMount` / `onDestroy`. Angular → `ngAfterViewInit` / `ngOnDestroy`.
53
147
 
148
+ First-party wrappers exist for the three largest frameworks and are built on
149
+ this package: [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react),
150
+ [`@seatlayer/vue`](https://www.npmjs.com/package/@seatlayer/vue), and
151
+ [`@seatlayer/angular`](https://www.npmjs.com/package/@seatlayer/angular).
152
+
153
+ ## Security boundary
154
+
155
+ The browser **selects and holds** inventory. Your trusted backend **inspects and
156
+ books** the hold after payment or order validation.
157
+
158
+ - Never expose a SeatLayer secret key in browser code or a bundled environment
159
+ variable.
160
+ - Send only the `holdId` and your normal checkout context to your backend.
161
+ - Calculate the charge from server-inspected hold items, not from browser input.
162
+ - Reuse your stable order id as `bookingRef` so a retried booking is idempotent.
163
+ - Organizer surfaces take a short-lived, event-scoped `mse_` browser grant held
164
+ in memory — never a tenant `sk_` secret, never a URL, storage, or log.
165
+
166
+ Read [how the integration works](https://docs.seatlayer.io/start/how-it-works/)
167
+ before connecting checkout.
168
+
54
169
  ## Embed the live control room
55
170
 
56
171
  `SeatManager` gives first-party dashboards and external platforms the same
@@ -118,13 +233,28 @@ callers must use an event-scoped `mse_` grant.
118
233
 
119
234
  ## Embed the chart Designer
120
235
 
121
- For organizer-facing venue design, use `EmbeddedDesigner`. Your backend mints the
122
- short-lived `designerUrl`; the browser receives no SeatLayer secret key. The wrapper
123
- creates the iframe, recreates it for a new session URL, and validates every
124
- `postMessage` by iframe source and exact Designer origin.
236
+ For organizer-facing venue design, use `EmbeddedDesigner`. Your backend
237
+ authenticates and authorizes the organizer, then requests a short-lived session
238
+ from SeatLayer with `sk_…`; SeatLayer mints the `dse_…` token and returns
239
+ `designerUrl`. Never expose the secret or call SeatLayer's Designer-session
240
+ endpoint from browser code. The wrapper creates the iframe, recreates it for a
241
+ new session URL, and validates every `postMessage` by iframe source and exact
242
+ Designer origin.
243
+
244
+ Start that required backend request on authenticated route intent or page load,
245
+ not on the final **Open Designer** click. Keep the response no-store and the
246
+ session in memory, and race its promise with the SDK import and editor shell.
247
+ An authenticated server-rendered page may instead include `designerUrl` in a
248
+ no-store bootstrap. The iframe still waits for the session; the win comes from
249
+ overlapping the trusted request with SDK and shell loading.
125
250
 
126
251
  ```js
127
- import { EmbeddedDesigner } from '@seatlayer/js';
252
+ const sdkPromise = import('@seatlayer/js');
253
+ const sessionPromise = requestDesignerSession(); // authenticated + no-store
254
+ const [{ EmbeddedDesigner }, session] = await Promise.all([
255
+ sdkPromise,
256
+ sessionPromise,
257
+ ]);
128
258
 
129
259
  const designer = new EmbeddedDesigner({
130
260
  container: '#venue-designer',
@@ -134,9 +264,9 @@ const designer = new EmbeddedDesigner({
134
264
  onPublished: ({ chartId }) => refreshVenue(chartId),
135
265
  onClose: () => closeVenueEditor(),
136
266
  onError: ({ code, message }) => showError(code ?? message),
137
- // Mint a fresh session when the user retries an expired/failed editor:
267
+ // Request a fresh session through your backend on retry/expiry:
138
268
  onRequestRelaunch: async () => {
139
- const next = await mintDesignerSession(session.chartId);
269
+ const next = await requestDesignerSession(session.chartId);
140
270
  designer.setDesignerUrl(next.designerUrl);
141
271
  },
142
272
  });
@@ -175,7 +305,7 @@ CSS files or external assets.
175
305
  | --- | --- | --- | --- |
176
306
  | `showLoadingState` | `boolean` | `true` | Render the built-in skeleton and error card. Set `false` when you draw your own chrome. |
177
307
  | `loadingTimeoutMs` | `number` | `20000` | If `ready` never arrives within this window, show the error card with a timeout message. |
178
- | `onRequestRelaunch` | `() => void` | — | Called by **"Try again"** _and_ by automatic renewal (below). Mint a fresh session and call `setDesignerUrl()`; the iframe recreates and returns to loading. When omitted, "Try again" reloads the current URL in place. |
308
+ | `onRequestRelaunch` | `() => void` | — | Called by **"Try again"** _and_ by automatic renewal (below). Request a fresh session through your backend and call `setDesignerUrl()`; the iframe recreates and returns to loading. When omitted, "Try again" reloads the current URL in place. |
179
309
  | `autoRenewSession` | `boolean` | `true`¹ | Silently renew the session before it expires and auto-recover once if an expiry error slips through. ¹Defaults `true` only when `onRequestRelaunch` is provided; a no-op without it. Set `false` for fully manual "Try again". |
180
310
 
181
311
  `setDesignerUrl()` always returns the host to the loading state, so a relaunch
@@ -183,20 +313,21 @@ flow needs no extra bookkeeping.
183
313
 
184
314
  ### Session lifecycle
185
315
 
186
- Designer sessions are **short-lived by design**: your backend mints a `dse_`
187
- token (default 1 hour, up to 4 hours via `expiresInSeconds`) and bakes it into
188
- `designerUrl`. Pick a TTL that fits how long organizers actually edit — longer is
189
- not automatically better; the renewal below keeps even a multi-hour session alive.
316
+ Designer sessions are **short-lived by design**: your backend authorizes and
317
+ requests one, then SeatLayer mints a `dse_` token (default 1 hour, up to 4 hours
318
+ via `expiresInSeconds`) into `designerUrl`. Pick a TTL that fits how long
319
+ organizers actually edit — longer is not automatically better; the renewal
320
+ below keeps even a multi-hour session alive.
190
321
 
191
- Provide `onRequestRelaunch` returning (or awaiting) a freshly minted session, and
192
- the SDK turns expiry into a non-event:
322
+ Provide `onRequestRelaunch` returning (or awaiting) a freshly requested session,
323
+ and the SDK turns expiry into a non-event:
193
324
 
194
325
  - **Silent proactive renewal.** From each `ready` message's `expiresAt` the SDK
195
326
  schedules an automatic relaunch shortly before the session lapses — ~3 minutes
196
327
  ahead, or, for a TTL under 15 minutes, after 80% of the remaining life (never
197
- sooner than 30s after `ready`). Your `onRequestRelaunch` mints a fresh session
198
- and swaps `designerUrl`, so editing continues with no expiry card. The timer
199
- re-arms from every `ready`.
328
+ sooner than 30s after `ready`). Your `onRequestRelaunch` requests a fresh
329
+ session through your backend and swaps `designerUrl`, so editing continues
330
+ with no expiry card. The timer re-arms from every `ready`.
200
331
  - **Automatic expiry recovery.** If an expiry error still arrives (a laptop that
201
332
  slept past the renewal window, say), the SDK makes **one** automatic relaunch
202
333
  attempt before showing the "Try again" card, and only falls back to the card if
@@ -210,9 +341,9 @@ const designer = new EmbeddedDesigner({
210
341
  container: '#venue-designer',
211
342
  designerUrl: session.designerUrl,
212
343
  expectedChartId: session.chartId,
213
- // Mint a fresh session on renewal, expiry recovery, or "Try again":
344
+ // Request a fresh session on renewal, expiry recovery, or "Try again":
214
345
  onRequestRelaunch: async () => {
215
- const next = await mintDesignerSession(session.chartId); // your backend, up to 4h TTL
346
+ const next = await requestDesignerSession(session.chartId); // your backend, up to 4h TTL
216
347
  designer.setDesignerUrl(next.designerUrl); // recreates the iframe
217
348
  },
218
349
  // autoRenewSession defaults to true because onRequestRelaunch is present.
@@ -223,7 +354,8 @@ designer.mount();
223
354
  ## API
224
355
 
225
356
  `new SeatingChart(options)` — options: `container` (selector or element, required),
226
- `event` (key, required), `apiBase?`, `maxSelection?` (default 10),
357
+ `event` (key, required), `apiBase?`, `publicKey?`,
358
+ `buyerAccessTokenProvider?`, `buyerAccessToken?`, `maxSelection?` (default 10),
227
359
  `selectedObjects?`, `selectableObjects?`, `numberOfPlacesToSelect?`,
228
360
  `selectionValidators?`,
229
361
  `onSelectionChange?`, `onSelectionValidityChange?`, `onHold?`,
@@ -304,17 +436,93 @@ Two limits worth knowing before switching it on:
304
436
  rather than back in your embed. In-page gateways never navigate away and
305
437
  confirm in place, as does an embed running on an allowed origin.
306
438
 
307
- ## Related resources
308
-
309
- - [Buyer SDK documentation](https://docs.seatlayer.io/buyer-sdk/install/)
310
- - [SeatingChart reference](https://docs.seatlayer.io/buyer-sdk/seating-chart/)
311
- - [Holds and checkout](https://docs.seatlayer.io/buyer-sdk/holds-and-checkout/)
312
- - [Complete checkout example](https://docs.seatlayer.io/examples/complete-checkout/)
313
- - [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react)
314
- - [React Native SDK](https://github.com/seatlayer/seatlayer-react-native)
315
- - [iOS SDK](https://github.com/seatlayer/seatlayer-ios)
316
- - [Flutter package](https://pub.dev/packages/seatlayer)
317
- - [Agent-readable documentation](https://docs.seatlayer.io/llms.txt)
439
+ ## Frequently asked questions
440
+
441
+ ### What is the best JavaScript library for seat maps and seat booking?
442
+
443
+ That depends on what you need to own. This package is a complete reserved-seating
444
+ runtime: it draws the venue, shows live availability, enforces selection rules,
445
+ and takes temporary holds that stop two buyers from taking the same seat. A
446
+ generic drawing library is lighter if you only need pictures of seats; the live
447
+ inventory, holds, and server-side booking are the parts SeatLayer provides, and
448
+ the same event also renders through the React, Vue, Angular, and native mobile
449
+ SDKs.
450
+
451
+ ### How do I add a seat map to a plain JavaScript page?
452
+
453
+ Load the hosted bundle with a `<script>` tag or install `@seatlayer/js`, give a
454
+ container a definite height, construct `SeatPicker` or `SeatingChart` with your
455
+ event key, and call `render()`. The install snippet above is the whole
456
+ integration; the
457
+ [buyer SDK installation guide](https://docs.seatlayer.io/buyer-sdk/install/)
458
+ covers options, events, and the framework variants.
459
+
460
+ ### Does it render in the page or in an iframe?
461
+
462
+ `SeatPicker` and `SeatingChart` render directly into the element you give them,
463
+ so your own styles and layout apply. Embedding in an iframe is supported too —
464
+ `attachPickerFrame` wires the host side of the resize and fullscreen protocol,
465
+ verifying the message origin. The organizer Designer is deliberately
466
+ iframe-only, so no Designer credential ever reaches the host bundle.
467
+
468
+ ### How do temporary seat holds work?
469
+
470
+ When a buyer commits to a selection, `hold()` reserves that inventory against
471
+ concurrent buyers for a limited checkout window and returns an opaque `holdId`.
472
+ The hold lapses on its own if checkout never completes, `resumeHold()` restores
473
+ it after a same-tab checkout navigation or a reload, and `releaseLabels()` gives
474
+ back part of it. This is what prevents double-selling without locking seats
475
+ forever.
476
+
477
+ ### Can I use my own payment provider?
478
+
479
+ Yes. By default no payment code is downloaded at all. The widget hands your code
480
+ a `holdId` and a self-contained `CheckoutHandoff` with priced line items, your
481
+ backend charges through whatever provider you already use, and it then books the
482
+ hold through the
483
+ [server-side checkout flow](https://docs.seatlayer.io/buyer-sdk/holds-and-checkout/).
484
+ The opt-in `checkout: 'hosted'` mode documented above exists only for hosts with
485
+ no backend.
486
+
487
+ ### Are TypeScript types included?
488
+
489
+ Yes. The package ships its own declarations for ESM and CommonJS, for both the
490
+ root entry and the `@seatlayer/js/manager` subpath — there is no `@types/*`
491
+ package to add. Declarations are validated at release by `publint` and
492
+ `arethetypeswrong`.
493
+
494
+ ## Continue your JavaScript integration
495
+
496
+ - [Follow the buyer SDK installation guide](https://docs.seatlayer.io/buyer-sdk/install/)
497
+ for the hosted script, ESM, and framework variants.
498
+ - [Read the SeatingChart reference](https://docs.seatlayer.io/buyer-sdk/seating-chart/)
499
+ for the complete chart API.
500
+ - [Connect seat holds to secure server-side checkout](https://docs.seatlayer.io/buyer-sdk/holds-and-checkout/)
501
+ without putting booking credentials in the browser.
502
+ - [Run the complete checkout example](https://docs.seatlayer.io/examples/complete-checkout/)
503
+ to connect a buyer hold id to payment and idempotent booking.
504
+ - [Compare SeatLayer's mobile seat map SDKs](https://docs.seatlayer.io/buyer-sdk/mobile/)
505
+ when the same event also has to render in native apps.
506
+ - [Read the embedded Designer guide](https://docs.seatlayer.io/platform/embedded-designer/)
507
+ to let organizers draw their own venues inside your product.
508
+ - [Explore the 3D seating chart](https://seatlayer.io/3d-seat-map/) for the
509
+ interactive venue view buyers can switch to from the map.
510
+ - [Point AI coding agents at the SeatLayer docs index](https://docs.seatlayer.io/llms.txt)
511
+ (`llms.txt`) for an agent-readable map of the documentation.
512
+
513
+ ## SeatLayer SDK ecosystem
514
+
515
+ | Surface | Package or source |
516
+ | --- | --- |
517
+ | JavaScript | [`@seatlayer/js`](https://www.npmjs.com/package/@seatlayer/js) (this package) |
518
+ | React | [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react) |
519
+ | Vue | [`@seatlayer/vue`](https://www.npmjs.com/package/@seatlayer/vue) |
520
+ | Angular | [`@seatlayer/angular`](https://www.npmjs.com/package/@seatlayer/angular) |
521
+ | React Native | [`@seatlayer/react-native`](https://www.npmjs.com/package/@seatlayer/react-native) |
522
+ | iOS | [`seatlayer-ios`](https://github.com/seatlayer/seatlayer-ios) |
523
+ | Flutter | [`seatlayer`](https://pub.dev/packages/seatlayer) |
524
+ | Android | [`seatlayer-android`](https://github.com/seatlayer/seatlayer-android) |
525
+ | Server SDKs | [Node.js, Python, PHP, Ruby, .NET, Java, and Go](https://docs.seatlayer.io/server-sdk/install/) |
318
526
 
319
527
  ## License
320
528