@bookitive/js 0.1.2 → 0.1.3

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.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** @example "VALIDATION_FAILED" */
1
2
  declare enum ResponseType {
2
3
  ErrInvalidPayload = "INVALID_PAYLOAD",
3
4
  ErrValidationFailed = "VALIDATION_FAILED",
@@ -15,9 +16,11 @@ interface DtoPublicAvailability {
15
16
  /**
16
17
  * ReservedSeats marks which unavailable seats are merely reserved and may
17
18
  * free up again — present only when the event shares reserved status.
19
+ * @uniqueItems false
18
20
  */
19
21
  reservedSeats?: string[];
20
22
  ticketTypeRemaining?: Record<string, number>;
23
+ /** @uniqueItems false */
21
24
  unavailableSeats?: string[];
22
25
  }
23
26
  interface DtoPublicEvent {
@@ -25,9 +28,11 @@ interface DtoPublicEvent {
25
28
  /**
26
29
  * Floors lets a host page render its floor tabs without loading the full
27
30
  * seating payload; ids match the seating endpoint's floors.
31
+ * @uniqueItems false
28
32
  */
29
33
  floors?: DtoPublicFloorInfo[];
30
34
  org?: DtoPublicOrg;
35
+ /** @uniqueItems false */
31
36
  ticketTypes?: DtoPublicTicketType[];
32
37
  }
33
38
  interface DtoPublicEventInfo {
@@ -40,22 +45,27 @@ interface DtoPublicEventInfo {
40
45
  startTime?: string;
41
46
  }
42
47
  interface DtoPublicFloor {
48
+ /** @uniqueItems false */
43
49
  cons?: string[];
44
50
  description?: string;
45
51
  id?: string;
46
52
  mode?: 'single' | 'sections';
47
53
  name?: string;
48
54
  position?: number;
55
+ /** @uniqueItems false */
49
56
  pros?: string[];
57
+ /** @uniqueItems false */
50
58
  sections?: DtoPublicSection[];
51
59
  }
52
60
  interface DtoPublicFloorInfo {
61
+ /** @uniqueItems false */
53
62
  cons?: string[];
54
63
  description?: string;
55
64
  id?: string;
56
65
  mode?: 'single' | 'sections';
57
66
  name?: string;
58
67
  position?: number;
68
+ /** @uniqueItems false */
59
69
  pros?: string[];
60
70
  }
61
71
  interface DtoPublicGAArea {
@@ -98,18 +108,22 @@ interface DtoPublicSeat {
98
108
  y?: number;
99
109
  }
100
110
  interface DtoPublicSeating {
111
+ /** @uniqueItems false */
101
112
  floors?: DtoPublicFloor[];
102
113
  }
103
114
  interface DtoPublicSection {
104
115
  decorations?: object;
116
+ /** @uniqueItems false */
105
117
  gaAreas?: DtoPublicGAArea[];
106
118
  h?: number;
107
119
  id?: string;
108
120
  name?: string;
109
121
  polygon?: object;
110
122
  prefix?: string;
123
+ /** @uniqueItems false */
111
124
  seats?: DtoPublicSeat[];
112
125
  settings?: object;
126
+ /** @uniqueItems false */
113
127
  tables?: DtoPublicTable[];
114
128
  w?: number;
115
129
  x?: number;
@@ -123,6 +137,7 @@ interface DtoPublicTable {
123
137
  radius?: number;
124
138
  rotation?: number;
125
139
  shape?: 'round' | 'rect' | 'row';
140
+ /** @uniqueItems false */
126
141
  sides?: number[];
127
142
  spacing?: number;
128
143
  w?: number;
@@ -131,6 +146,7 @@ interface DtoPublicTable {
131
146
  }
132
147
  interface DtoPublicTicketType {
133
148
  color?: string;
149
+ /** @uniqueItems false */
134
150
  cons?: string[];
135
151
  description?: string;
136
152
  id?: string;
@@ -143,6 +159,7 @@ interface DtoPublicTicketType {
143
159
  minPerOrder?: number;
144
160
  name?: string;
145
161
  priceCents?: number;
162
+ /** @uniqueItems false */
146
163
  pros?: string[];
147
164
  saleEndTime?: string;
148
165
  saleStartTime?: string;
@@ -156,7 +173,10 @@ interface PublichandlerPayloadPublicOrder {
156
173
  /** @maxLength 50 */
157
174
  phone?: string;
158
175
  };
159
- /** @minItems 1 */
176
+ /**
177
+ * @minItems 1
178
+ * @uniqueItems false
179
+ */
160
180
  items: PublichandlerPayloadPublicOrderItem[];
161
181
  }
162
182
  interface PublichandlerPayloadPublicOrderItem {
@@ -173,7 +193,6 @@ interface ResponseAPIError {
173
193
  msg: string;
174
194
  timestamp?: string;
175
195
  traceId?: string;
176
- /** @example "VALIDATION_FAILED" */
177
196
  type: ResponseType;
178
197
  }
179
198
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/generated/api.ts","../src/live.ts","../src/client.ts"],"sourcesContent":["/* eslint-disable */\n/* tslint:disable */\n// @ts-nocheck\n/*\n * ---------------------------------------------------------------\n * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##\n * ## ##\n * ## AUTHOR: acacode ##\n * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##\n * ---------------------------------------------------------------\n */\n\nexport enum ResponseType {\n\tErrInvalidPayload = 'INVALID_PAYLOAD',\n\tErrValidationFailed = 'VALIDATION_FAILED',\n\tErrNotFound = 'NOT_FOUND',\n\tErrNotImplemented = 'NOT_IMPLEMENTED',\n\tErrConflict = 'CONFLICT',\n\tErrInternal = 'INTERNAL_ERROR',\n\tErrUnauthorized = 'UNAUTHORIZED',\n\tErrForbidden = 'FORBIDDEN',\n\tErrMissingOrganizationID = 'MISSING_ORGANIZATION_ID',\n\tErrMissingUserID = 'MISSING_USER_ID',\n}\n\nexport interface DtoPublicAvailability {\n\tgaRemaining?: Record<string, number>;\n\t/**\n\t * ReservedSeats marks which unavailable seats are merely reserved and may\n\t * free up again — present only when the event shares reserved status.\n\t */\n\treservedSeats?: string[];\n\tticketTypeRemaining?: Record<string, number>;\n\tunavailableSeats?: string[];\n}\n\nexport interface DtoPublicEvent {\n\tevent?: DtoPublicEventInfo;\n\t/**\n\t * Floors lets a host page render its floor tabs without loading the full\n\t * seating payload; ids match the seating endpoint's floors.\n\t */\n\tfloors?: DtoPublicFloorInfo[];\n\torg?: DtoPublicOrg;\n\tticketTypes?: DtoPublicTicketType[];\n}\n\nexport interface DtoPublicEventInfo {\n\tcurrency?: string;\n\tendTime?: string;\n\tholdTtlSeconds?: number;\n\tlocationName?: string;\n\tname?: string;\n\tslug?: string;\n\tstartTime?: string;\n}\n\nexport interface DtoPublicFloor {\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tmode?: 'single' | 'sections';\n\tname?: string;\n\tposition?: number;\n\tpros?: string[];\n\tsections?: DtoPublicSection[];\n}\n\nexport interface DtoPublicFloorInfo {\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tmode?: 'single' | 'sections';\n\tname?: string;\n\tposition?: number;\n\tpros?: string[];\n}\n\nexport interface DtoPublicGAArea {\n\tcapacity?: number;\n\th?: number;\n\tid?: string;\n\tlabel?: string;\n\trotation?: number;\n\tticketTypeId?: string;\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicOrder {\n\tcurrency?: string;\n\texpiresAt?: string;\n\tpayment?: DtoPublicPaymentDetail;\n\treference?: string;\n\tstatus?: 'pending' | 'paid' | 'cancelled' | 'expired';\n\ttotalCents?: number;\n}\n\nexport interface DtoPublicOrg {\n\taccentColor?: string;\n\tlogoUrl?: string;\n\tname?: string;\n\tslug?: string;\n}\n\nexport interface DtoPublicPaymentDetail {\n\t/** BankAccount is the organizer's free-form payment destination. */\n\tbankAccount?: string;\n\t/** VariableSymbol identifies the payment — it equals the order reference. */\n\tvariableSymbol?: string;\n}\n\nexport interface DtoPublicSeat {\n\tcode?: string;\n\tid?: string;\n\ttableId?: string;\n\tticketTypeId?: string;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicSeating {\n\tfloors?: DtoPublicFloor[];\n}\n\nexport interface DtoPublicSection {\n\tdecorations?: object;\n\tgaAreas?: DtoPublicGAArea[];\n\th?: number;\n\tid?: string;\n\tname?: string;\n\tpolygon?: object;\n\tprefix?: string;\n\tseats?: DtoPublicSeat[];\n\tsettings?: object;\n\ttables?: DtoPublicTable[];\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicTable {\n\tcurve?: number;\n\th?: number;\n\tid?: string;\n\tnumber?: number;\n\tradius?: number;\n\trotation?: number;\n\tshape?: 'round' | 'rect' | 'row';\n\tsides?: number[];\n\tspacing?: number;\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicTicketType {\n\tcolor?: string;\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tkind?: 'seated' | 'standing';\n\tmaxPerOrder?: number;\n\t/**\n\t * MinPerOrder appears only when it is a real constraint (> 1) — the\n\t * limit applies to orders that include this type at all.\n\t */\n\tminPerOrder?: number;\n\tname?: string;\n\tpriceCents?: number;\n\tpros?: string[];\n\tsaleEndTime?: string;\n\tsaleStartTime?: string;\n}\n\nexport interface PublichandlerPayloadPublicOrder {\n\tcaptchaToken?: string;\n\tcustomer: {\n\t\temail: string;\n\t\t/** @maxLength 200 */\n\t\tname: string;\n\t\t/** @maxLength 50 */\n\t\tphone?: string;\n\t};\n\t/** @minItems 1 */\n\titems: PublichandlerPayloadPublicOrderItem[];\n}\n\nexport interface PublichandlerPayloadPublicOrderItem {\n\tgaAreaId?: string;\n\t/** @min 1 */\n\tquantity: number;\n\tseatId?: string;\n\tticketTypeId: string;\n}\n\nexport interface ResponseAPIError {\n\tdata?: any;\n\tfields?: Record<string, string>;\n\t/** @example \"see fields\" */\n\tmsg: string;\n\ttimestamp?: string;\n\ttraceId?: string;\n\t/** @example \"VALIDATION_FAILED\" */\n\ttype: ResponseType;\n}\n","// Live availability over websocket: {\"event\":\"startstate\"|\"seat\", data}.\n// Startstate re-fires on every reconnect, so consumers treat it as the\n// resync point and apply deltas on top.\nimport type { DtoPublicAvailability } from './generated/api.js';\n\n/** One seat changing state. \"reserved\" appears only when the event shares\n * reserved status publicly — a reserved seat may free up again. */\nexport interface SeatDelta {\n\tseatId: string;\n\ttaken: boolean;\n\tstatus: 'free' | 'reserved' | 'taken';\n}\n\nexport interface LiveHandlers {\n\t/** Full snapshot — on connect and on every reconnect. */\n\tonStartstate?: (availability: DtoPublicAvailability) => void;\n\t/** One seat changed. */\n\tonSeat?: (delta: SeatDelta) => void;\n\t/** Connection state changes (drive a \"live\" indicator if you like). */\n\tonConnectionChange?: (connected: boolean) => void;\n}\n\nconst INITIAL_BACKOFF_MS = 1000;\nconst MAX_BACKOFF_MS = 15000;\n\nexport class LiveSubscription {\n\t#url: string;\n\t#handlers: LiveHandlers;\n\t#ws: WebSocket | null = null;\n\t#backoff = INITIAL_BACKOFF_MS;\n\t#retry: ReturnType<typeof setTimeout> | null = null;\n\t#closed = false;\n\n\tconstructor(url: string, handlers: LiveHandlers) {\n\t\tthis.#url = url.replace(/^http/, 'ws');\n\t\tthis.#handlers = handlers;\n\t\tthis.#connect();\n\t}\n\n\tclose(): void {\n\t\tthis.#closed = true;\n\t\tif (this.#retry) clearTimeout(this.#retry);\n\t\tthis.#ws?.close();\n\t}\n\n\t#connect(): void {\n\t\tif (this.#closed) return;\n\t\tconst ws = new WebSocket(this.#url);\n\t\tthis.#ws = ws;\n\t\tws.onopen = () => {\n\t\t\tthis.#backoff = INITIAL_BACKOFF_MS;\n\t\t\tthis.#handlers.onConnectionChange?.(true);\n\t\t};\n\t\tws.onmessage = (event) => {\n\t\t\tlet message: { event?: string; data?: unknown };\n\t\t\ttry {\n\t\t\t\tmessage = JSON.parse(event.data as string);\n\t\t\t} catch {\n\t\t\t\treturn; // ignore malformed / non-JSON frames rather than throwing\n\t\t\t}\n\t\t\tif (message.event === 'startstate') {\n\t\t\t\tthis.#handlers.onStartstate?.(message.data as DtoPublicAvailability);\n\t\t\t} else if (message.event === 'seat') {\n\t\t\t\tthis.#handlers.onSeat?.(message.data as SeatDelta);\n\t\t\t}\n\t\t};\n\t\tws.onclose = () => {\n\t\t\tthis.#handlers.onConnectionChange?.(false);\n\t\t\tif (this.#closed) return;\n\t\t\t// Equal-jitter backoff: reconnect somewhere in [backoff/2, backoff) so a\n\t\t\t// mass disconnect doesn't produce a synchronized reconnect thundering herd.\n\t\t\tconst delay = this.#backoff / 2 + Math.random() * (this.#backoff / 2);\n\t\t\tthis.#retry = setTimeout(() => this.#connect(), delay);\n\t\t\tthis.#backoff = Math.min(this.#backoff * 2, MAX_BACKOFF_MS);\n\t\t};\n\t}\n}\n","// The typed core of @bookitive/js: a thin fetch wrapper over the public\n// checkout API, addressed by org + event slug. All response and payload types\n// are generated from the backend's public swagger — they cannot drift.\nimport { ResponseType } from './generated/api.js';\nimport type {\n\tDtoPublicAvailability,\n\tDtoPublicEvent,\n\tDtoPublicOrder,\n\tDtoPublicSeating,\n\tPublichandlerPayloadPublicOrder,\n\tResponseAPIError,\n} from './generated/api.js';\nimport { LiveSubscription, type LiveHandlers } from './live.js';\n\nexport interface BookitiveClientOptions {\n\t/** API origin, e.g. \"https://api.bookitive.com\" (no trailing slash). */\n\tbaseUrl: string;\n\t/** Organization slug — the {org} in events.bookitive.com/{org}/{event}. */\n\torg: string;\n\t/** Event slug. */\n\tevent: string;\n\t/** Custom fetch (SSR frameworks pass their own). Defaults to global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** API failure with the backend's error envelope attached. */\nexport class BookitiveError extends Error {\n\treadonly status: number;\n\t/** The backend error code (e.g. ResponseType.ErrConflict), or \"UNKNOWN\" when\n\t * the response carried no JSON envelope. */\n\treadonly type: ResponseType | 'UNKNOWN';\n\n\tconstructor(status: number, body: ResponseAPIError | undefined, fallback: string) {\n\t\tsuper(body?.msg ?? fallback);\n\t\tthis.name = 'BookitiveError';\n\t\tthis.status = status;\n\t\tthis.type = body?.type ?? 'UNKNOWN';\n\t}\n\n\t/** The selection raced another buyer — refresh availability and reselect. */\n\tget isConflict(): boolean {\n\t\treturn this.type === ResponseType.ErrConflict || this.status === 409;\n\t}\n}\n\nexport class BookitiveClient {\n\treadonly #base: string;\n\treadonly #fetch: typeof fetch;\n\n\tconstructor(options: BookitiveClientOptions) {\n\t\tthis.#base = `${options.baseUrl.replace(/\\/$/, '')}/public/v1/orgs/${encodeURIComponent(\n\t\t\toptions.org\n\t\t)}/events/${encodeURIComponent(options.event)}`;\n\t\t// bind, or a browser's fetch throws \"Illegal invocation\" when called\n\t\t// detached from window\n\t\tthis.#fetch = options.fetch ?? ((...args) => fetch(...args));\n\t}\n\n\t/** Event identity, org branding, priced ticket types, and floor tabs. */\n\tevent(): Promise<DtoPublicEvent> {\n\t\treturn this.#get<DtoPublicEvent>('');\n\t}\n\n\t/** Static chart geometry: floors → sections → tables, seats, GA areas. */\n\tseating(): Promise<DtoPublicSeating> {\n\t\treturn this.#get<DtoPublicSeating>('/seating');\n\t}\n\n\t/** Live sellability snapshot (poll it, or use live() for push updates). */\n\tavailability(): Promise<DtoPublicAvailability> {\n\t\treturn this.#get<DtoPublicAvailability>('/availability');\n\t}\n\n\t/**\n\t * Places a bank-transfer reservation: seats are held atomically for the\n\t * event's hold TTL and payment instructions are emailed (and returned).\n\t * A 409 (error.isConflict) means a seat was just taken — refresh and\n\t * reselect.\n\t */\n\tasync checkout(order: PublichandlerPayloadPublicOrder): Promise<DtoPublicOrder> {\n\t\tconst res = await this.#fetch(`${this.#base}/orders`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(order),\n\t\t});\n\t\treturn this.#parse<DtoPublicOrder>(res, 'checkout failed');\n\t}\n\n\t/**\n\t * Subscribes to live availability over websocket: `startstate` fires with\n\t * the full snapshot on every (re)connect, then `seat` deltas stream in.\n\t * Reconnects automatically with backoff; call close() when done.\n\t */\n\tlive(handlers: LiveHandlers): LiveSubscription {\n\t\treturn new LiveSubscription(`${this.#base}/live`, handlers);\n\t}\n\n\tasync #get<T>(path: string): Promise<T> {\n\t\tconst res = await this.#fetch(`${this.#base}${path}`);\n\t\treturn this.#parse<T>(res, `request failed: ${path || '/'}`);\n\t}\n\n\tasync #parse<T>(res: Response, fallback: string): Promise<T> {\n\t\tif (!res.ok) {\n\t\t\tlet body: ResponseAPIError | undefined;\n\t\t\ttry {\n\t\t\t\tbody = (await res.json()) as ResponseAPIError;\n\t\t\t} catch {\n\t\t\t\t// non-JSON error body — the fallback message covers it\n\t\t\t}\n\t\t\tthrow new BookitiveError(res.status, body, fallback);\n\t\t}\n\t\t// No content (204) or an explicitly empty body — don't call res.json(),\n\t\t// which would throw on an empty stream.\n\t\tif (res.status === 204 || res.headers.get('content-length') === '0') {\n\t\t\treturn undefined as T;\n\t\t}\n\t\treturn (await res.json()) as T;\n\t}\n}\n"],"mappings":"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","names":["ResponseType"]}
1
+ {"version":3,"sources":["../src/generated/api.ts","../src/live.ts","../src/client.ts"],"sourcesContent":["/* eslint-disable */\n/* tslint:disable */\n// @ts-nocheck\n/*\n * ---------------------------------------------------------------\n * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##\n * ## ##\n * ## AUTHOR: acacode ##\n * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##\n * ---------------------------------------------------------------\n */\n\n/** @example \"VALIDATION_FAILED\" */\nexport enum ResponseType {\n\tErrInvalidPayload = 'INVALID_PAYLOAD',\n\tErrValidationFailed = 'VALIDATION_FAILED',\n\tErrNotFound = 'NOT_FOUND',\n\tErrNotImplemented = 'NOT_IMPLEMENTED',\n\tErrConflict = 'CONFLICT',\n\tErrInternal = 'INTERNAL_ERROR',\n\tErrUnauthorized = 'UNAUTHORIZED',\n\tErrForbidden = 'FORBIDDEN',\n\tErrMissingOrganizationID = 'MISSING_ORGANIZATION_ID',\n\tErrMissingUserID = 'MISSING_USER_ID',\n}\n\nexport interface DtoPublicAvailability {\n\tgaRemaining?: Record<string, number>;\n\t/**\n\t * ReservedSeats marks which unavailable seats are merely reserved and may\n\t * free up again — present only when the event shares reserved status.\n\t * @uniqueItems false\n\t */\n\treservedSeats?: string[];\n\tticketTypeRemaining?: Record<string, number>;\n\t/** @uniqueItems false */\n\tunavailableSeats?: string[];\n}\n\nexport interface DtoPublicEvent {\n\tevent?: DtoPublicEventInfo;\n\t/**\n\t * Floors lets a host page render its floor tabs without loading the full\n\t * seating payload; ids match the seating endpoint's floors.\n\t * @uniqueItems false\n\t */\n\tfloors?: DtoPublicFloorInfo[];\n\torg?: DtoPublicOrg;\n\t/** @uniqueItems false */\n\tticketTypes?: DtoPublicTicketType[];\n}\n\nexport interface DtoPublicEventInfo {\n\tcurrency?: string;\n\tendTime?: string;\n\tholdTtlSeconds?: number;\n\tlocationName?: string;\n\tname?: string;\n\tslug?: string;\n\tstartTime?: string;\n}\n\nexport interface DtoPublicFloor {\n\t/** @uniqueItems false */\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tmode?: 'single' | 'sections';\n\tname?: string;\n\tposition?: number;\n\t/** @uniqueItems false */\n\tpros?: string[];\n\t/** @uniqueItems false */\n\tsections?: DtoPublicSection[];\n}\n\nexport interface DtoPublicFloorInfo {\n\t/** @uniqueItems false */\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tmode?: 'single' | 'sections';\n\tname?: string;\n\tposition?: number;\n\t/** @uniqueItems false */\n\tpros?: string[];\n}\n\nexport interface DtoPublicGAArea {\n\tcapacity?: number;\n\th?: number;\n\tid?: string;\n\tlabel?: string;\n\trotation?: number;\n\tticketTypeId?: string;\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicOrder {\n\tcurrency?: string;\n\texpiresAt?: string;\n\tpayment?: DtoPublicPaymentDetail;\n\treference?: string;\n\tstatus?: 'pending' | 'paid' | 'cancelled' | 'expired';\n\ttotalCents?: number;\n}\n\nexport interface DtoPublicOrg {\n\taccentColor?: string;\n\tlogoUrl?: string;\n\tname?: string;\n\tslug?: string;\n}\n\nexport interface DtoPublicPaymentDetail {\n\t/** BankAccount is the organizer's free-form payment destination. */\n\tbankAccount?: string;\n\t/** VariableSymbol identifies the payment — it equals the order reference. */\n\tvariableSymbol?: string;\n}\n\nexport interface DtoPublicSeat {\n\tcode?: string;\n\tid?: string;\n\ttableId?: string;\n\tticketTypeId?: string;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicSeating {\n\t/** @uniqueItems false */\n\tfloors?: DtoPublicFloor[];\n}\n\nexport interface DtoPublicSection {\n\tdecorations?: object;\n\t/** @uniqueItems false */\n\tgaAreas?: DtoPublicGAArea[];\n\th?: number;\n\tid?: string;\n\tname?: string;\n\tpolygon?: object;\n\tprefix?: string;\n\t/** @uniqueItems false */\n\tseats?: DtoPublicSeat[];\n\tsettings?: object;\n\t/** @uniqueItems false */\n\ttables?: DtoPublicTable[];\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicTable {\n\tcurve?: number;\n\th?: number;\n\tid?: string;\n\tnumber?: number;\n\tradius?: number;\n\trotation?: number;\n\tshape?: 'round' | 'rect' | 'row';\n\t/** @uniqueItems false */\n\tsides?: number[];\n\tspacing?: number;\n\tw?: number;\n\tx?: number;\n\ty?: number;\n}\n\nexport interface DtoPublicTicketType {\n\tcolor?: string;\n\t/** @uniqueItems false */\n\tcons?: string[];\n\tdescription?: string;\n\tid?: string;\n\tkind?: 'seated' | 'standing';\n\tmaxPerOrder?: number;\n\t/**\n\t * MinPerOrder appears only when it is a real constraint (> 1) — the\n\t * limit applies to orders that include this type at all.\n\t */\n\tminPerOrder?: number;\n\tname?: string;\n\tpriceCents?: number;\n\t/** @uniqueItems false */\n\tpros?: string[];\n\tsaleEndTime?: string;\n\tsaleStartTime?: string;\n}\n\nexport interface PublichandlerPayloadPublicOrder {\n\tcaptchaToken?: string;\n\tcustomer: {\n\t\temail: string;\n\t\t/** @maxLength 200 */\n\t\tname: string;\n\t\t/** @maxLength 50 */\n\t\tphone?: string;\n\t};\n\t/**\n\t * @minItems 1\n\t * @uniqueItems false\n\t */\n\titems: PublichandlerPayloadPublicOrderItem[];\n}\n\nexport interface PublichandlerPayloadPublicOrderItem {\n\tgaAreaId?: string;\n\t/** @min 1 */\n\tquantity: number;\n\tseatId?: string;\n\tticketTypeId: string;\n}\n\nexport interface ResponseAPIError {\n\tdata?: any;\n\tfields?: Record<string, string>;\n\t/** @example \"see fields\" */\n\tmsg: string;\n\ttimestamp?: string;\n\ttraceId?: string;\n\ttype: ResponseType;\n}\n","// Live availability over websocket: {\"event\":\"startstate\"|\"seat\", data}.\n// Startstate re-fires on every reconnect, so consumers treat it as the\n// resync point and apply deltas on top.\nimport type { DtoPublicAvailability } from './generated/api.js';\n\n/** One seat changing state. \"reserved\" appears only when the event shares\n * reserved status publicly — a reserved seat may free up again. */\nexport interface SeatDelta {\n\tseatId: string;\n\ttaken: boolean;\n\tstatus: 'free' | 'reserved' | 'taken';\n}\n\nexport interface LiveHandlers {\n\t/** Full snapshot — on connect and on every reconnect. */\n\tonStartstate?: (availability: DtoPublicAvailability) => void;\n\t/** One seat changed. */\n\tonSeat?: (delta: SeatDelta) => void;\n\t/** Connection state changes (drive a \"live\" indicator if you like). */\n\tonConnectionChange?: (connected: boolean) => void;\n}\n\nconst INITIAL_BACKOFF_MS = 1000;\nconst MAX_BACKOFF_MS = 15000;\n\nexport class LiveSubscription {\n\t#url: string;\n\t#handlers: LiveHandlers;\n\t#ws: WebSocket | null = null;\n\t#backoff = INITIAL_BACKOFF_MS;\n\t#retry: ReturnType<typeof setTimeout> | null = null;\n\t#closed = false;\n\n\tconstructor(url: string, handlers: LiveHandlers) {\n\t\tthis.#url = url.replace(/^http/, 'ws');\n\t\tthis.#handlers = handlers;\n\t\tthis.#connect();\n\t}\n\n\tclose(): void {\n\t\tthis.#closed = true;\n\t\tif (this.#retry) clearTimeout(this.#retry);\n\t\tthis.#ws?.close();\n\t}\n\n\t#connect(): void {\n\t\tif (this.#closed) return;\n\t\tconst ws = new WebSocket(this.#url);\n\t\tthis.#ws = ws;\n\t\tws.onopen = () => {\n\t\t\tthis.#backoff = INITIAL_BACKOFF_MS;\n\t\t\tthis.#handlers.onConnectionChange?.(true);\n\t\t};\n\t\tws.onmessage = (event) => {\n\t\t\tlet message: { event?: string; data?: unknown };\n\t\t\ttry {\n\t\t\t\tmessage = JSON.parse(event.data as string);\n\t\t\t} catch {\n\t\t\t\treturn; // ignore malformed / non-JSON frames rather than throwing\n\t\t\t}\n\t\t\tif (message.event === 'startstate') {\n\t\t\t\tthis.#handlers.onStartstate?.(message.data as DtoPublicAvailability);\n\t\t\t} else if (message.event === 'seat') {\n\t\t\t\tthis.#handlers.onSeat?.(message.data as SeatDelta);\n\t\t\t}\n\t\t};\n\t\tws.onclose = () => {\n\t\t\tthis.#handlers.onConnectionChange?.(false);\n\t\t\tif (this.#closed) return;\n\t\t\t// Equal-jitter backoff: reconnect somewhere in [backoff/2, backoff) so a\n\t\t\t// mass disconnect doesn't produce a synchronized reconnect thundering herd.\n\t\t\tconst delay = this.#backoff / 2 + Math.random() * (this.#backoff / 2);\n\t\t\tthis.#retry = setTimeout(() => this.#connect(), delay);\n\t\t\tthis.#backoff = Math.min(this.#backoff * 2, MAX_BACKOFF_MS);\n\t\t};\n\t}\n}\n","// The typed core of @bookitive/js: a thin fetch wrapper over the public\n// checkout API, addressed by org + event slug. All response and payload types\n// are generated from the backend's public swagger — they cannot drift.\nimport { ResponseType } from './generated/api.js';\nimport type {\n\tDtoPublicAvailability,\n\tDtoPublicEvent,\n\tDtoPublicOrder,\n\tDtoPublicSeating,\n\tPublichandlerPayloadPublicOrder,\n\tResponseAPIError,\n} from './generated/api.js';\nimport { LiveSubscription, type LiveHandlers } from './live.js';\n\nexport interface BookitiveClientOptions {\n\t/** API origin, e.g. \"https://api.bookitive.com\" (no trailing slash). */\n\tbaseUrl: string;\n\t/** Organization slug — the {org} in events.bookitive.com/{org}/{event}. */\n\torg: string;\n\t/** Event slug. */\n\tevent: string;\n\t/** Custom fetch (SSR frameworks pass their own). Defaults to global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** API failure with the backend's error envelope attached. */\nexport class BookitiveError extends Error {\n\treadonly status: number;\n\t/** The backend error code (e.g. ResponseType.ErrConflict), or \"UNKNOWN\" when\n\t * the response carried no JSON envelope. */\n\treadonly type: ResponseType | 'UNKNOWN';\n\n\tconstructor(status: number, body: ResponseAPIError | undefined, fallback: string) {\n\t\tsuper(body?.msg ?? fallback);\n\t\tthis.name = 'BookitiveError';\n\t\tthis.status = status;\n\t\tthis.type = body?.type ?? 'UNKNOWN';\n\t}\n\n\t/** The selection raced another buyer — refresh availability and reselect. */\n\tget isConflict(): boolean {\n\t\treturn this.type === ResponseType.ErrConflict || this.status === 409;\n\t}\n}\n\nexport class BookitiveClient {\n\treadonly #base: string;\n\treadonly #fetch: typeof fetch;\n\n\tconstructor(options: BookitiveClientOptions) {\n\t\tthis.#base = `${options.baseUrl.replace(/\\/$/, '')}/public/v1/orgs/${encodeURIComponent(\n\t\t\toptions.org\n\t\t)}/events/${encodeURIComponent(options.event)}`;\n\t\t// bind, or a browser's fetch throws \"Illegal invocation\" when called\n\t\t// detached from window\n\t\tthis.#fetch = options.fetch ?? ((...args) => fetch(...args));\n\t}\n\n\t/** Event identity, org branding, priced ticket types, and floor tabs. */\n\tevent(): Promise<DtoPublicEvent> {\n\t\treturn this.#get<DtoPublicEvent>('');\n\t}\n\n\t/** Static chart geometry: floors → sections → tables, seats, GA areas. */\n\tseating(): Promise<DtoPublicSeating> {\n\t\treturn this.#get<DtoPublicSeating>('/seating');\n\t}\n\n\t/** Live sellability snapshot (poll it, or use live() for push updates). */\n\tavailability(): Promise<DtoPublicAvailability> {\n\t\treturn this.#get<DtoPublicAvailability>('/availability');\n\t}\n\n\t/**\n\t * Places a bank-transfer reservation: seats are held atomically for the\n\t * event's hold TTL and payment instructions are emailed (and returned).\n\t * A 409 (error.isConflict) means a seat was just taken — refresh and\n\t * reselect.\n\t */\n\tasync checkout(order: PublichandlerPayloadPublicOrder): Promise<DtoPublicOrder> {\n\t\tconst res = await this.#fetch(`${this.#base}/orders`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(order),\n\t\t});\n\t\treturn this.#parse<DtoPublicOrder>(res, 'checkout failed');\n\t}\n\n\t/**\n\t * Subscribes to live availability over websocket: `startstate` fires with\n\t * the full snapshot on every (re)connect, then `seat` deltas stream in.\n\t * Reconnects automatically with backoff; call close() when done.\n\t */\n\tlive(handlers: LiveHandlers): LiveSubscription {\n\t\treturn new LiveSubscription(`${this.#base}/live`, handlers);\n\t}\n\n\tasync #get<T>(path: string): Promise<T> {\n\t\tconst res = await this.#fetch(`${this.#base}${path}`);\n\t\treturn this.#parse<T>(res, `request failed: ${path || '/'}`);\n\t}\n\n\tasync #parse<T>(res: Response, fallback: string): Promise<T> {\n\t\tif (!res.ok) {\n\t\t\tlet body: ResponseAPIError | undefined;\n\t\t\ttry {\n\t\t\t\tbody = (await res.json()) as ResponseAPIError;\n\t\t\t} catch {\n\t\t\t\t// non-JSON error body — the fallback message covers it\n\t\t\t}\n\t\t\tthrow new BookitiveError(res.status, body, fallback);\n\t\t}\n\t\t// No content (204) or an explicitly empty body — don't call res.json(),\n\t\t// which would throw on an empty stream.\n\t\tif (res.status === 204 || res.headers.get('content-length') === '0') {\n\t\t\treturn undefined as T;\n\t\t}\n\t\treturn (await res.json()) as T;\n\t}\n}\n"],"mappings":"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","names":["ResponseType"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bookitive/js",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Typed client for the Bookitive public checkout API — event info, seating, live availability, and orders.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "vitest": "^3.0.5"
28
28
  },
29
29
  "scripts": {
30
- "generate": "swagger-typescript-api generate -p ${PUBLIC_SWAGGER_JSON:-http://localhost:3000/public/v1/swagger/doc.json} -o ./src/generated -n api.ts --no-client",
30
+ "generate": "swagger-typescript-api generate -p ${PUBLIC_OPENAPI_JSON:-http://localhost:3000/public/v1/openapi.json} -o ./src/generated -n api.ts --no-client",
31
31
  "build": "tsup src/index.ts --format esm --dts --clean --sourcemap",
32
32
  "check": "tsc --noEmit",
33
33
  "test": "vitest run",