@seatlayer/server 0.1.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/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/index.cjs +693 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +637 -0
- package/dist/index.d.ts +637 -0
- package/dist/index.js +657 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors.
|
|
3
|
+
*
|
|
4
|
+
* The API answers failures with `{ error, code?, message? }` and a status. A
|
|
5
|
+
* generated client would surface that as one opaque exception and leave every
|
|
6
|
+
* caller string-matching on `error`. The cases below are the ones an
|
|
7
|
+
* integration actually branches on — a sold-out seat is a business outcome that
|
|
8
|
+
* belongs in an `if`, not in a `catch` that also swallows a bad key.
|
|
9
|
+
*/
|
|
10
|
+
/** Raw error envelope as the API sends it. */
|
|
11
|
+
interface ApiErrorBody {
|
|
12
|
+
error?: string;
|
|
13
|
+
code?: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
declare class SeatLayerError extends Error {
|
|
18
|
+
readonly status: number;
|
|
19
|
+
/** Machine-readable code: `body.code ?? body.error`. */
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly body: ApiErrorBody;
|
|
22
|
+
/** Correlation id from `X-Request-ID`. Quote it in support requests. */
|
|
23
|
+
readonly requestId: string | null;
|
|
24
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null);
|
|
25
|
+
}
|
|
26
|
+
/** 401/403 — bad key, revoked key, or a live key used against a test event. */
|
|
27
|
+
declare class SeatLayerAuthError extends SeatLayerError {
|
|
28
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null);
|
|
29
|
+
/**
|
|
30
|
+
* True when the key's mode and the event's mode disagree — the most common
|
|
31
|
+
* cause of a "works locally, 403s in production" report.
|
|
32
|
+
*/
|
|
33
|
+
get isModeMismatch(): boolean;
|
|
34
|
+
}
|
|
35
|
+
declare class SeatLayerNotFoundError extends SeatLayerError {
|
|
36
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 409 — the seats moved under you. This is a normal outcome in ticketing, not
|
|
40
|
+
* an exceptional one: two buyers wanted the same seat and one lost.
|
|
41
|
+
*/
|
|
42
|
+
declare class SeatLayerConflictError extends SeatLayerError {
|
|
43
|
+
/** Per-object conflicts, when the endpoint reports them. */
|
|
44
|
+
readonly conflicts: Array<{
|
|
45
|
+
label: string;
|
|
46
|
+
status: string;
|
|
47
|
+
}>;
|
|
48
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null);
|
|
49
|
+
/** True when best-available could not find enough free inventory. */
|
|
50
|
+
get isSoldOut(): boolean;
|
|
51
|
+
}
|
|
52
|
+
/** 422 — the request was understood and rejected. */
|
|
53
|
+
declare class SeatLayerValidationError extends SeatLayerError {
|
|
54
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 429. `retryAfterSeconds` comes from the `Retry-After` header when present and
|
|
58
|
+
* falls back to the JSON field, so callers get a real number either way.
|
|
59
|
+
*/
|
|
60
|
+
declare class SeatLayerRateLimitError extends SeatLayerError {
|
|
61
|
+
readonly retryAfterSeconds: number;
|
|
62
|
+
constructor(status: number, body: ApiErrorBody, requestId: string | null, retryAfterSeconds: number);
|
|
63
|
+
}
|
|
64
|
+
/** The request never got an answer: DNS, TLS, socket, or an abort. */
|
|
65
|
+
declare class SeatLayerConnectionError extends Error {
|
|
66
|
+
readonly cause: unknown;
|
|
67
|
+
constructor(message: string, cause: unknown);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The transport: auth, idempotency, retry, and error mapping.
|
|
72
|
+
*
|
|
73
|
+
* This is the layer that decides how the SDK behaves when the network or the
|
|
74
|
+
* API misbehaves, which is most of what separates a usable client from a thin
|
|
75
|
+
* `fetch` wrapper.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
interface ClientOptions {
|
|
79
|
+
/** `sk_live_…` or `sk_test_…`. Never expose this to a browser. */
|
|
80
|
+
secretKey: string;
|
|
81
|
+
/** Override for self-hosted or staging. Defaults to the public API. */
|
|
82
|
+
baseUrl?: string;
|
|
83
|
+
/** Total attempts for retryable failures. Default 3 (two retries). */
|
|
84
|
+
maxRetries?: number;
|
|
85
|
+
/** Per-request timeout in ms. Default 30_000. */
|
|
86
|
+
timeoutMs?: number;
|
|
87
|
+
/** Injectable for tests and for runtimes with a non-global fetch. */
|
|
88
|
+
fetch?: typeof globalThis.fetch;
|
|
89
|
+
}
|
|
90
|
+
interface RequestOptions {
|
|
91
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
92
|
+
body?: unknown;
|
|
93
|
+
/**
|
|
94
|
+
* Explicit Idempotency-Key. Omit and mutating requests get a generated one —
|
|
95
|
+
* see `shouldSendIdempotencyKey`.
|
|
96
|
+
*/
|
|
97
|
+
idempotencyKey?: string;
|
|
98
|
+
signal?: AbortSignal;
|
|
99
|
+
}
|
|
100
|
+
declare class HttpClient {
|
|
101
|
+
#private;
|
|
102
|
+
readonly baseUrl: string;
|
|
103
|
+
/** Whether this client is pointed at test-mode or live-mode data. */
|
|
104
|
+
readonly mode: 'live' | 'test' | 'unknown';
|
|
105
|
+
constructor(options: ClientOptions);
|
|
106
|
+
request<T>(method: string, path: string, options?: RequestOptions): Promise<T>;
|
|
107
|
+
get<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
108
|
+
post<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
109
|
+
put<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
110
|
+
patch<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
111
|
+
delete<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Shared shapes. Kept hand-written so the names read like the docs. */
|
|
115
|
+
type KeyMode = 'live' | 'test';
|
|
116
|
+
interface ChartMeta {
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
status: string;
|
|
120
|
+
workspaceId?: string;
|
|
121
|
+
externalRef?: string | null;
|
|
122
|
+
updatedAt: number;
|
|
123
|
+
createdAt: number;
|
|
124
|
+
[key: string]: unknown;
|
|
125
|
+
}
|
|
126
|
+
interface Chart {
|
|
127
|
+
meta: ChartMeta;
|
|
128
|
+
/** The chart document. Authored in the Designer; opaque to most backends. */
|
|
129
|
+
doc?: Record<string, unknown>;
|
|
130
|
+
}
|
|
131
|
+
interface EventMeta {
|
|
132
|
+
key: string;
|
|
133
|
+
id: string;
|
|
134
|
+
chartId: string;
|
|
135
|
+
name?: string;
|
|
136
|
+
slug?: string | null;
|
|
137
|
+
startsAt?: number | null;
|
|
138
|
+
venue?: string | null;
|
|
139
|
+
currency?: string | null;
|
|
140
|
+
externalRef?: string | null;
|
|
141
|
+
[key: string]: unknown;
|
|
142
|
+
}
|
|
143
|
+
/** A priced line item. `unitPrice` is in `currency`, not in minor units. */
|
|
144
|
+
interface HoldLineItem {
|
|
145
|
+
label: string;
|
|
146
|
+
objectId: string;
|
|
147
|
+
objectType: 'seat' | 'booth' | 'ga' | 'table';
|
|
148
|
+
categoryKey: string;
|
|
149
|
+
tierId: string | null;
|
|
150
|
+
unitPrice: number;
|
|
151
|
+
currency: string;
|
|
152
|
+
quantity?: number;
|
|
153
|
+
capacity?: number;
|
|
154
|
+
}
|
|
155
|
+
interface HoldResult {
|
|
156
|
+
ok: true;
|
|
157
|
+
holdId: string;
|
|
158
|
+
/** Epoch ms. The hold is gone after this unless booked or extended. */
|
|
159
|
+
expiresAt: number;
|
|
160
|
+
items: HoldLineItem[];
|
|
161
|
+
labels?: string[];
|
|
162
|
+
}
|
|
163
|
+
interface BookResult {
|
|
164
|
+
ok: true;
|
|
165
|
+
labels?: string[];
|
|
166
|
+
items?: HoldLineItem[];
|
|
167
|
+
bookingRef?: string;
|
|
168
|
+
}
|
|
169
|
+
interface Workspace {
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
status: 'active' | 'disabled';
|
|
173
|
+
isDefault: boolean;
|
|
174
|
+
externalRef?: string | null;
|
|
175
|
+
}
|
|
176
|
+
interface Webhook {
|
|
177
|
+
id: string;
|
|
178
|
+
url: string;
|
|
179
|
+
events: string[];
|
|
180
|
+
status?: string;
|
|
181
|
+
[key: string]: unknown;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* What a manage-session token is allowed to do in the browser.
|
|
185
|
+
*
|
|
186
|
+
* `event:cancel` un-books paid inventory. It is separated from `event:block`
|
|
187
|
+
* deliberately — a box-office view that only needs to hold seats back should
|
|
188
|
+
* never be able to cancel a sale.
|
|
189
|
+
*/
|
|
190
|
+
type ManageCapability = 'event:view' | 'event:block' | 'event:cancel' | 'event:reports';
|
|
191
|
+
interface ManageSession {
|
|
192
|
+
token: string;
|
|
193
|
+
expiresAt: number;
|
|
194
|
+
capabilities: ManageCapability[];
|
|
195
|
+
[key: string]: unknown;
|
|
196
|
+
}
|
|
197
|
+
interface DesignerSession {
|
|
198
|
+
token: string;
|
|
199
|
+
expiresAt: number;
|
|
200
|
+
[key: string]: unknown;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface ChartListOptions {
|
|
204
|
+
workspaceId?: string;
|
|
205
|
+
externalRef?: string;
|
|
206
|
+
archived?: boolean;
|
|
207
|
+
/** Page size. Clamped server-side; asking for more is not an error. */
|
|
208
|
+
limit?: number;
|
|
209
|
+
cursor?: string;
|
|
210
|
+
}
|
|
211
|
+
interface ChartPage {
|
|
212
|
+
charts: ChartMeta[];
|
|
213
|
+
/** Absent once the list is exhausted. */
|
|
214
|
+
nextCursor?: string;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Charts are the seat-map definitions events are created from.
|
|
218
|
+
*
|
|
219
|
+
* If your organisers draw their own venues in the embedded Designer, you still
|
|
220
|
+
* need this: `createDesignerSession` requires a chartId that must already
|
|
221
|
+
* exist, so the usual platform flow is copy a template here, then hand the
|
|
222
|
+
* organiser a Designer session for it.
|
|
223
|
+
*/
|
|
224
|
+
declare class Charts {
|
|
225
|
+
#private;
|
|
226
|
+
constructor(http: HttpClient);
|
|
227
|
+
/**
|
|
228
|
+
* One page of charts. Pass `cursor` from the previous page's `nextCursor`;
|
|
229
|
+
* its absence means the list is exhausted.
|
|
230
|
+
*/
|
|
231
|
+
list(options?: ChartListOptions): Promise<ChartPage>;
|
|
232
|
+
/**
|
|
233
|
+
* Every chart, paging transparently.
|
|
234
|
+
*
|
|
235
|
+
* An async iterator rather than an array: the whole point of paginating was
|
|
236
|
+
* to stop loading an unbounded list into memory, and returning `ChartMeta[]`
|
|
237
|
+
* would hand that problem straight back to the caller.
|
|
238
|
+
*
|
|
239
|
+
* for await (const chart of seatlayer.charts.listAll()) { … }
|
|
240
|
+
*/
|
|
241
|
+
listAll(options?: Omit<ChartListOptions, 'cursor'>): AsyncGenerator<ChartMeta>;
|
|
242
|
+
create(params: {
|
|
243
|
+
name: string;
|
|
244
|
+
doc?: Record<string, unknown>;
|
|
245
|
+
externalRef?: string;
|
|
246
|
+
workspaceId?: string;
|
|
247
|
+
}, options?: {
|
|
248
|
+
idempotencyKey?: string;
|
|
249
|
+
}): Promise<{
|
|
250
|
+
meta: ChartMeta;
|
|
251
|
+
}>;
|
|
252
|
+
retrieve(chartId: string): Promise<Chart>;
|
|
253
|
+
/**
|
|
254
|
+
* Replace a chart document.
|
|
255
|
+
*
|
|
256
|
+
* `expectedUpdatedAt` is required by the API for optimistic concurrency and
|
|
257
|
+
* is not optional here either: without it two concurrent writers silently
|
|
258
|
+
* overwrite each other, and a seat map is exactly the kind of document where
|
|
259
|
+
* that loses work. Read it from `retrieve()` immediately before writing.
|
|
260
|
+
*
|
|
261
|
+
* The Designer is the authoring surface. Reach for this for bulk programmatic
|
|
262
|
+
* edits and migrations, not for drawing.
|
|
263
|
+
*/
|
|
264
|
+
update(chartId: string, params: {
|
|
265
|
+
doc: Record<string, unknown>;
|
|
266
|
+
expectedUpdatedAt: number;
|
|
267
|
+
name?: string;
|
|
268
|
+
}): Promise<{
|
|
269
|
+
meta: ChartMeta;
|
|
270
|
+
}>;
|
|
271
|
+
delete(chartId: string): Promise<void>;
|
|
272
|
+
/** Copy a chart — the usual way to provision a venue from a template. */
|
|
273
|
+
copy(chartId: string, options?: {
|
|
274
|
+
idempotencyKey?: string;
|
|
275
|
+
}): Promise<{
|
|
276
|
+
meta: ChartMeta;
|
|
277
|
+
}>;
|
|
278
|
+
archive(chartId: string): Promise<{
|
|
279
|
+
meta: ChartMeta;
|
|
280
|
+
}>;
|
|
281
|
+
unarchive(chartId: string): Promise<{
|
|
282
|
+
meta: ChartMeta;
|
|
283
|
+
}>;
|
|
284
|
+
/** Publish the draft. An event can only be created from a published chart. */
|
|
285
|
+
publish(chartId: string): Promise<{
|
|
286
|
+
meta: ChartMeta;
|
|
287
|
+
}>;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
interface EventListOptions {
|
|
291
|
+
workspaceId?: string;
|
|
292
|
+
externalRef?: string;
|
|
293
|
+
/** Page size. Clamped server-side; asking for more is not an error. */
|
|
294
|
+
limit?: number;
|
|
295
|
+
cursor?: string;
|
|
296
|
+
/** Include live availability counts. One server round-trip per event. */
|
|
297
|
+
counts?: boolean;
|
|
298
|
+
}
|
|
299
|
+
interface EventPage {
|
|
300
|
+
events: EventMeta[];
|
|
301
|
+
/** Absent once the list is exhausted. */
|
|
302
|
+
nextCursor?: string;
|
|
303
|
+
}
|
|
304
|
+
declare class Events {
|
|
305
|
+
#private;
|
|
306
|
+
constructor(http: HttpClient);
|
|
307
|
+
/**
|
|
308
|
+
* One page of events. Pass `cursor` from the previous page's `nextCursor`.
|
|
309
|
+
*
|
|
310
|
+
* Live availability `counts` cost one round-trip per event server-side. They
|
|
311
|
+
* are included by default because most callers want them; pass
|
|
312
|
+
* `counts: false` when paging a whole catalogue, where you almost certainly
|
|
313
|
+
* do not.
|
|
314
|
+
*/
|
|
315
|
+
list(options?: EventListOptions): Promise<EventPage>;
|
|
316
|
+
/**
|
|
317
|
+
* Every event, paging transparently. Defaults to `counts: false` — you are
|
|
318
|
+
* walking the whole list, so per-event availability is rarely what you want
|
|
319
|
+
* and always what it costs.
|
|
320
|
+
*
|
|
321
|
+
* for await (const event of seatlayer.events.listAll()) { … }
|
|
322
|
+
*/
|
|
323
|
+
listAll(options?: Omit<EventListOptions, 'cursor'>): AsyncGenerator<EventMeta>;
|
|
324
|
+
create(params: {
|
|
325
|
+
chartId: string;
|
|
326
|
+
name?: string;
|
|
327
|
+
slug?: string;
|
|
328
|
+
startsAt?: number;
|
|
329
|
+
venue?: string;
|
|
330
|
+
externalRef?: string;
|
|
331
|
+
/** Three-letter override. Defaults to the organisation currency. */
|
|
332
|
+
currency?: string;
|
|
333
|
+
}, options?: {
|
|
334
|
+
idempotencyKey?: string;
|
|
335
|
+
}): Promise<{
|
|
336
|
+
meta: EventMeta;
|
|
337
|
+
}>;
|
|
338
|
+
retrieve(eventKey: string): Promise<{
|
|
339
|
+
meta: EventMeta;
|
|
340
|
+
counts?: Record<string, number>;
|
|
341
|
+
}>;
|
|
342
|
+
update(eventKey: string, params: Record<string, unknown>): Promise<{
|
|
343
|
+
meta: EventMeta;
|
|
344
|
+
}>;
|
|
345
|
+
delete(eventKey: string): Promise<void>;
|
|
346
|
+
/** Move a live event onto the latest published version of its chart. */
|
|
347
|
+
updateChart(eventKey: string): Promise<unknown>;
|
|
348
|
+
/** Stop buyer sales. Existing holds keep their TTL. */
|
|
349
|
+
close(eventKey: string): Promise<unknown>;
|
|
350
|
+
reopen(eventKey: string): Promise<unknown>;
|
|
351
|
+
archive(eventKey: string): Promise<unknown>;
|
|
352
|
+
/** Read the checkout window (ms) buyers get for this event. */
|
|
353
|
+
retrieveHoldTtl(eventKey: string): Promise<{
|
|
354
|
+
holdTtlMs: number;
|
|
355
|
+
}>;
|
|
356
|
+
updateHoldTtl(eventKey: string, holdTtlMs: number): Promise<unknown>;
|
|
357
|
+
retrieveReport(eventKey: string): Promise<unknown>;
|
|
358
|
+
retrieveLog(eventKey: string): Promise<unknown>;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Holds, booking, blocking, availability.
|
|
363
|
+
*
|
|
364
|
+
* Two complete flows, both first-class:
|
|
365
|
+
*
|
|
366
|
+
* browser holds → `retrieveHold` for authoritative pricing → charge → `book({holdId})`
|
|
367
|
+
* backend books labels directly — box office, phone sales, comps
|
|
368
|
+
*
|
|
369
|
+
* Never price from what the browser tells you. `retrieveHold` is the
|
|
370
|
+
* authoritative answer, which is why it exists as a separate call.
|
|
371
|
+
*/
|
|
372
|
+
declare class Inventory {
|
|
373
|
+
#private;
|
|
374
|
+
constructor(http: HttpClient);
|
|
375
|
+
hold(eventKey: string, params: {
|
|
376
|
+
labels?: string[];
|
|
377
|
+
selections?: Array<{
|
|
378
|
+
label: string;
|
|
379
|
+
tierId?: string | null;
|
|
380
|
+
quantity?: number;
|
|
381
|
+
}>;
|
|
382
|
+
/** Overrides the event's checkout window for this hold. */
|
|
383
|
+
ttlMs?: number;
|
|
384
|
+
replaceHoldId?: string;
|
|
385
|
+
}, options?: {
|
|
386
|
+
idempotencyKey?: string;
|
|
387
|
+
}): Promise<HoldResult>;
|
|
388
|
+
/**
|
|
389
|
+
* Ask us to pick the best free objects and hold them.
|
|
390
|
+
*
|
|
391
|
+
* The picker is the same one the buyer widget uses, so a phone order and a
|
|
392
|
+
* web order get the same answer for the same inventory. `qty` above the
|
|
393
|
+
* server cap is clamped, not rejected.
|
|
394
|
+
*/
|
|
395
|
+
holdBestAvailable(eventKey: string, params: {
|
|
396
|
+
qty: number;
|
|
397
|
+
categoryKey?: string;
|
|
398
|
+
zoneId?: string;
|
|
399
|
+
ttlMs?: number;
|
|
400
|
+
}, options?: {
|
|
401
|
+
idempotencyKey?: string;
|
|
402
|
+
}): Promise<HoldResult>;
|
|
403
|
+
/**
|
|
404
|
+
* Pick and book in one call — the box-office shape, where payment is already
|
|
405
|
+
* taken and there is no buyer session to hold against.
|
|
406
|
+
*
|
|
407
|
+
* Prefer this over holdBestAvailable-then-book for that case: a failure
|
|
408
|
+
* between the two calls would strand inventory until the TTL expired.
|
|
409
|
+
*/
|
|
410
|
+
bookBestAvailable(eventKey: string, params: {
|
|
411
|
+
qty: number;
|
|
412
|
+
bookingRef: string;
|
|
413
|
+
categoryKey?: string;
|
|
414
|
+
zoneId?: string;
|
|
415
|
+
}, options?: {
|
|
416
|
+
idempotencyKey?: string;
|
|
417
|
+
}): Promise<BookResult>;
|
|
418
|
+
/**
|
|
419
|
+
* Push an active hold's expiry out by a fresh window before it lapses.
|
|
420
|
+
*
|
|
421
|
+
* Use this rather than release-and-re-hold when an order is taking longer
|
|
422
|
+
* than the checkout window — invoiced sales, a phone order on hold. Releasing
|
|
423
|
+
* first hands the seats to whoever is racing for them in between. The server
|
|
424
|
+
* clamps the window and the DO caps how many times one hold can be renewed;
|
|
425
|
+
* a hold that is gone, expired, or at its cap answers 409 `cannot_extend`.
|
|
426
|
+
*/
|
|
427
|
+
extendHold(eventKey: string, params: {
|
|
428
|
+
holdId: string;
|
|
429
|
+
ttlMs?: number;
|
|
430
|
+
}): Promise<HoldResult>;
|
|
431
|
+
/** Authoritative items and prices for a hold. Charge from this, not the browser. */
|
|
432
|
+
retrieveHold(eventKey: string, holdId: string): Promise<{
|
|
433
|
+
items: HoldLineItem[];
|
|
434
|
+
expiresAt: number;
|
|
435
|
+
currency: string;
|
|
436
|
+
}>;
|
|
437
|
+
/** Free a hold early. Requires both the labels and the hold id. */
|
|
438
|
+
release(eventKey: string, params: {
|
|
439
|
+
labels: string[];
|
|
440
|
+
holdId: string;
|
|
441
|
+
}): Promise<unknown>;
|
|
442
|
+
book(eventKey: string, params: {
|
|
443
|
+
/** Book a held selection… */
|
|
444
|
+
holdId?: string;
|
|
445
|
+
/** …or book labels outright, with no prior hold. */
|
|
446
|
+
labels?: string[];
|
|
447
|
+
bookingRef?: string;
|
|
448
|
+
}, options?: {
|
|
449
|
+
idempotencyKey?: string;
|
|
450
|
+
}): Promise<BookResult>;
|
|
451
|
+
boxOfficeBook(eventKey: string, params: {
|
|
452
|
+
labels: string[];
|
|
453
|
+
bookingRef: string;
|
|
454
|
+
}, options?: {
|
|
455
|
+
idempotencyKey?: string;
|
|
456
|
+
}): Promise<BookResult>;
|
|
457
|
+
/** Reverse a booking. Requires a key with cancel authority. */
|
|
458
|
+
unbook(eventKey: string, params: {
|
|
459
|
+
labels: string[];
|
|
460
|
+
}): Promise<unknown>;
|
|
461
|
+
/** Hold inventory back from sale (house seats, holds for production). */
|
|
462
|
+
block(eventKey: string, params: {
|
|
463
|
+
labels: string[];
|
|
464
|
+
}): Promise<unknown>;
|
|
465
|
+
unblock(eventKey: string, params: {
|
|
466
|
+
labels: string[];
|
|
467
|
+
}): Promise<unknown>;
|
|
468
|
+
unblockAll(eventKey: string): Promise<unknown>;
|
|
469
|
+
retrieveAvailability(eventKey: string): Promise<unknown>;
|
|
470
|
+
updateAvailability(eventKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Short-lived, origin-bound browser tokens.
|
|
475
|
+
*
|
|
476
|
+
* The governing rule of this SDK: **it mints tokens, widgets consume them.**
|
|
477
|
+
* Your secret key never reaches a browser. You mint a scoped token here, hand
|
|
478
|
+
* it to your frontend, and our widget uses that.
|
|
479
|
+
*/
|
|
480
|
+
declare class Sessions {
|
|
481
|
+
#private;
|
|
482
|
+
constructor(http: HttpClient);
|
|
483
|
+
/**
|
|
484
|
+
* Mint a manage-session token for the control room.
|
|
485
|
+
*
|
|
486
|
+
* `capabilities` is required here even though the API defaults it. That
|
|
487
|
+
* default grants all four — including `event:cancel`, which un-books paid
|
|
488
|
+
* inventory. Granting the ability to reverse sales by forgetting an argument
|
|
489
|
+
* is not a default worth inheriting, so this SDK makes you say it.
|
|
490
|
+
*
|
|
491
|
+
* `allowedOrigin` must be an https origin; the token is bound to it.
|
|
492
|
+
*/
|
|
493
|
+
createManageSession(eventKey: string, params: {
|
|
494
|
+
allowedOrigin: string;
|
|
495
|
+
capabilities: ManageCapability[];
|
|
496
|
+
/** 300–14400. Defaults to 3600 server-side. */
|
|
497
|
+
expiresInSeconds?: number;
|
|
498
|
+
}): Promise<ManageSession>;
|
|
499
|
+
/** Revoke a manage token before it expires (staff logout, permission change). */
|
|
500
|
+
revokeManageSession(eventKey: string, sessionId: string): Promise<void>;
|
|
501
|
+
/**
|
|
502
|
+
* Mint a designer-session token so an organiser can edit a chart inside your
|
|
503
|
+
* own UI. Requires a chartId that already exists — create or copy one first.
|
|
504
|
+
*/
|
|
505
|
+
createDesignerSession(params: {
|
|
506
|
+
workspaceId: string;
|
|
507
|
+
chartId: string;
|
|
508
|
+
allowedOrigin: string;
|
|
509
|
+
authority?: 'read-only' | 'edit' | 'publish';
|
|
510
|
+
mode?: 'normal' | 'safe';
|
|
511
|
+
expiresInSeconds?: number;
|
|
512
|
+
}): Promise<DesignerSession>;
|
|
513
|
+
revokeDesignerSession(sessionId: string): Promise<void>;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
declare class Webhooks {
|
|
517
|
+
#private;
|
|
518
|
+
constructor(http: HttpClient);
|
|
519
|
+
list(): Promise<{
|
|
520
|
+
webhooks: Webhook[];
|
|
521
|
+
}>;
|
|
522
|
+
create(params: {
|
|
523
|
+
url: string;
|
|
524
|
+
events: string[];
|
|
525
|
+
}): Promise<{
|
|
526
|
+
webhook: Webhook;
|
|
527
|
+
secret?: string;
|
|
528
|
+
}>;
|
|
529
|
+
update(webhookId: string, params: Partial<{
|
|
530
|
+
url: string;
|
|
531
|
+
events: string[];
|
|
532
|
+
status: string;
|
|
533
|
+
}>): Promise<{
|
|
534
|
+
webhook: Webhook;
|
|
535
|
+
}>;
|
|
536
|
+
delete(webhookId: string): Promise<void>;
|
|
537
|
+
listDeliveries(webhookId: string): Promise<{
|
|
538
|
+
deliveries: unknown[];
|
|
539
|
+
}>;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Workspaces isolate one tenant's charts and events from another's. A platform
|
|
544
|
+
* typically provisions one per organiser at signup and disables it on churn.
|
|
545
|
+
*/
|
|
546
|
+
declare class Workspaces {
|
|
547
|
+
#private;
|
|
548
|
+
constructor(http: HttpClient);
|
|
549
|
+
list(): Promise<{
|
|
550
|
+
workspaces: Workspace[];
|
|
551
|
+
}>;
|
|
552
|
+
create(params: {
|
|
553
|
+
name: string;
|
|
554
|
+
externalRef?: string;
|
|
555
|
+
}, options?: {
|
|
556
|
+
idempotencyKey?: string;
|
|
557
|
+
}): Promise<{
|
|
558
|
+
workspace: Workspace;
|
|
559
|
+
}>;
|
|
560
|
+
retrieve(workspaceId: string): Promise<{
|
|
561
|
+
workspace: Workspace;
|
|
562
|
+
}>;
|
|
563
|
+
/**
|
|
564
|
+
* Rename, re-reference, or disable a workspace.
|
|
565
|
+
*
|
|
566
|
+
* The organisation's default workspace cannot be disabled — the API answers
|
|
567
|
+
* 409 `default_workspace_required`. Promote another one first.
|
|
568
|
+
*/
|
|
569
|
+
update(workspaceId: string, params: Partial<{
|
|
570
|
+
name: string;
|
|
571
|
+
externalRef: string | null;
|
|
572
|
+
status: 'active' | 'disabled';
|
|
573
|
+
isDefault: true;
|
|
574
|
+
}>): Promise<{
|
|
575
|
+
workspace: Workspace;
|
|
576
|
+
}>;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
interface VerifyWebhookOptions {
|
|
580
|
+
/**
|
|
581
|
+
* The raw request body, exactly as received — a string or Buffer, never a
|
|
582
|
+
* parsed object. Express: `express.raw({ type: 'application/json' })`.
|
|
583
|
+
*/
|
|
584
|
+
payload: string | Uint8Array;
|
|
585
|
+
/** The `X-SeatLayer-Signature` header value (`sha256=<hex>`). */
|
|
586
|
+
signature: string | null | undefined;
|
|
587
|
+
/** The signing secret from webhook creation. */
|
|
588
|
+
secret: string;
|
|
589
|
+
}
|
|
590
|
+
declare class WebhookVerificationError extends Error {
|
|
591
|
+
constructor(message: string);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Verify a delivery and return its parsed payload.
|
|
595
|
+
*
|
|
596
|
+
* Throws `WebhookVerificationError` on any failure — treat that as "this did
|
|
597
|
+
* not come from SeatLayer" and respond 400 without processing it.
|
|
598
|
+
*
|
|
599
|
+
* NOTE ON REPLAY: deliveries are currently signed over the body only, with no
|
|
600
|
+
* timestamp header and so no tolerance window. Replay protection is therefore
|
|
601
|
+
* yours to enforce: every event carries an `occurrenceId`, and the correct
|
|
602
|
+
* pattern is to record processed ids and ignore repeats. Do not skip this — a
|
|
603
|
+
* captured delivery stays valid indefinitely.
|
|
604
|
+
*/
|
|
605
|
+
declare function verifyWebhook<T = Record<string, unknown>>(options: VerifyWebhookOptions): T;
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* SeatLayer server SDK.
|
|
609
|
+
*
|
|
610
|
+
* Secret-key only. This package must never be bundled into a browser — see the
|
|
611
|
+
* session-minting helpers for how browser surfaces get scoped tokens instead.
|
|
612
|
+
*/
|
|
613
|
+
|
|
614
|
+
declare class SeatLayer {
|
|
615
|
+
#private;
|
|
616
|
+
readonly charts: Charts;
|
|
617
|
+
readonly events: Events;
|
|
618
|
+
readonly inventory: Inventory;
|
|
619
|
+
readonly sessions: Sessions;
|
|
620
|
+
readonly webhooks: Webhooks;
|
|
621
|
+
readonly workspaces: Workspaces;
|
|
622
|
+
/** `test` or `live`, derived from the key prefix. */
|
|
623
|
+
readonly mode: 'live' | 'test' | 'unknown';
|
|
624
|
+
constructor(options: ClientOptions | string);
|
|
625
|
+
/** Dependency-aware readiness probe. Unauthenticated upstream. */
|
|
626
|
+
ready(): Promise<{
|
|
627
|
+
ok: boolean;
|
|
628
|
+
[key: string]: unknown;
|
|
629
|
+
}>;
|
|
630
|
+
/**
|
|
631
|
+
* Escape hatch for surface this SDK does not wrap yet. Carries the same auth,
|
|
632
|
+
* retry, idempotency and error mapping as everything else.
|
|
633
|
+
*/
|
|
634
|
+
request<T>(method: string, path: string, options?: Parameters<HttpClient['request']>[2]): Promise<T>;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export { type ApiErrorBody, type BookResult, type Chart, type ChartMeta, type ClientOptions, type DesignerSession, type EventMeta, type HoldLineItem, type HoldResult, type KeyMode, type ManageCapability, type ManageSession, type RequestOptions, SeatLayer, SeatLayerAuthError, SeatLayerConflictError, SeatLayerConnectionError, SeatLayerError, SeatLayerNotFoundError, SeatLayerRateLimitError, SeatLayerValidationError, type VerifyWebhookOptions, type Webhook, WebhookVerificationError, type Workspace, SeatLayer as default, verifyWebhook };
|