@getmicdrop/venue-calendar 4.2.2 → 4.2.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/{ArrowLeftIcon-DQ-h5PcH.js → ArrowLeftIcon-CxZXP_IT.js} +1 -1
- package/dist/{Badge-M6qZyfTF.js → Badge-Bv_MT-Vt.js} +10 -9
- package/dist/BlockPlaceholder-HZ6Coko5.js +52 -0
- package/dist/Button-C4uFgl7L.js +2141 -0
- package/dist/{Calendar-BX22svpz.js → Calendar-BKefLfIt.js} +292 -290
- package/dist/CalendarFoundryView-tDmFCrJ3.js +22292 -0
- package/dist/{CalendarIcon-DR197Ioz.js → CalendarIcon-CLGR_zlO.js} +1 -1
- package/dist/{CartView-B2VtVvZM.js → CartView-CHFlfWS9.js} +651 -644
- package/dist/{Checkout-BTqfjvDp.js → Checkout-C-A4t1eE.js} +92 -91
- package/dist/Checkout-CRX7dcRr.js +1807 -0
- package/dist/{CheckoutTimer-Cng5tcGO.js → CheckoutTimer-d3KUbevy.js} +5 -5
- package/dist/{ChevronDownIcon-C_RiK-BW.js → ChevronDownIcon-YtBeSqjf.js} +1 -1
- package/dist/{ClockIcon-BOJENuPq.js → ClockIcon-a9tJQ5El.js} +1 -1
- package/dist/{CloseIcon-Rc7tpX2a.js → CloseIcon-DSURK5co.js} +1 -1
- package/dist/CloseOutline-qpVa62mu.js +13 -0
- package/dist/{CollectionView-A1zP8yz5.js → CollectionView-BiBMllyw.js} +13 -12
- package/dist/CropImage-B0tj2_uN.js +404 -0
- package/dist/Event-1ZJVzqFN.js +3034 -0
- package/dist/{EventPage-hxrPKPhm.js → EventPage-C7K2yA4v.js} +168 -167
- package/dist/{Heading-B7VYbbfJ.js → Heading-Dfo3bjyn.js} +4 -3
- package/dist/Image-B3cEndLZ.js +87 -0
- package/dist/Input-DkYIFK4J.js +487 -0
- package/dist/{MailIcon-rxvK4Wga.js → MailIcon-DIrQpcGo.js} +1 -1
- package/dist/{Modal-BVD2O8hd.js → Modal-DrA1swbF.js} +2 -2
- package/dist/{ModalFooter-CfboEe1M.js → ModalFooter-r1NQNG9P.js} +59 -57
- package/dist/{PasswordInput-BAlq2j97.js → PasswordInput-DB4qa7kS.js} +4 -4
- package/dist/{ScarcityBadge-h7ygRD_C.js → ScarcityBadge-BJOm7_Ho.js} +4 -4
- package/dist/{SeriesPage-D-cwUNZM.js → SeriesPage-JVmqUSax.js} +5 -5
- package/dist/{Spinner-ChTN7t75.js → Spinner-BwiDys7C.js} +3 -3
- package/dist/{Success-CIAX5zmz.js → Success-DAE6gPZM.js} +77 -76
- package/dist/{TagIcon-V0qMu9wS.js → TagIcon-CrTNd8qE.js} +1 -1
- package/dist/{ViewTicketsEmbed-By-IcUJZ.js → ViewTicketsEmbed-Zx-mvP2p.js} +60 -59
- package/dist/{WarningCircleIcon-D32h6VDr.js → WarningCircleIcon-C5-op3Cy.js} +1 -1
- package/dist/{WarningTriIcon-BPDrCiKU.js → WarningTriIcon-BxIQn7c2.js} +1 -1
- package/dist/{__SKIP_PATHS__-DirqE5Xe.js → __SKIP_PATHS__-DyyiXBgB.js} +1 -1
- package/dist/api/types.d.ts +528 -528
- package/dist/{browser-25hnscei.js → browser-Um8Y6K99.js} +7 -7
- package/dist/{colors-5ifWyP6H.js → colors-MuuDk6KF.js} +30 -29
- package/dist/{constants-Dcj3kgZE.js → constants-CqrJv6nM.js} +73 -73
- package/dist/{copyToClipboard-CNxFW3ni.js → copyToClipboard-CTS9Wtmo.js} +1 -1
- package/dist/{createI18n-08XGDh1_.js → createI18n-DBUVdZra.js} +1 -1
- package/dist/{event-Cp5D4ctZ.js → event-BrptLro8.js} +1 -1
- package/dist/{event-transform-DSuEpMxr.js → event-transform-jFmHl0Qp.js} +4 -4
- package/dist/{eventStatusStream-CIZVH5Lp.js → eventStatusStream-D04pcbuu.js} +2 -2
- package/dist/{allowlist-BiUmz2AF.js → href-C8WGnROy.js} +21 -4
- package/dist/{i18n-CEeBd5Hi.js → i18n-CcJmTGJP.js} +11 -11
- package/dist/imageOptimizer-CB3wKJU8.js +47 -0
- package/dist/{labels-CtyfffZI.js → labels-Q4CaHsVM.js} +1 -1
- package/dist/{modalManager.svelte-BH-QJm9M.js → modalManager.svelte-qcVxl7C5.js} +2 -2
- package/dist/{order-totals-hcdvbJvw.js → order-totals-BImtvmoh.js} +15 -13
- package/dist/{orders-tzTe2hNM.js → orders-C8kt6c-E.js} +20 -19
- package/dist/{Input-W-QE9nWi.js → phoneUtils-FnBDCqO0.js} +694 -1132
- package/dist/{pixels-7kl8Fcjl.js → pixels-MEc7WYiV.js} +8 -7
- package/dist/{promo-BrMcoTYh.js → promo-DtLZRskK.js} +3 -3
- package/dist/{serverTotals-CpRaEe9K.js → serverTotals-BO126TTd.js} +1 -1
- package/dist/{shareCopyFeedback.svelte-DsyhrfiP.js → shareCopyFeedback.svelte-Dko8NIbm.js} +25 -25
- package/dist/{showcase-state-options-B2XfybZq.js → showcase-state-options-BoJxiEsg.js} +1 -1
- package/dist/sortable.esm--ZtTTTPp.js +1451 -0
- package/dist/timezones-C5l0SSHK.js +2030 -0
- package/dist/{to-event-card-props-VPne8W4I.js → to-event-card-props-BAHzloEA.js} +24 -23
- package/dist/{utils-DJVlBMbw.js → utils-Ts4-U13Y.js} +3 -3
- package/dist/venue-calendar.css +1 -1
- package/dist/venue-calendar.es.js +200 -199
- package/dist/venue-calendar.iife.js +63 -62
- package/dist/venue-calendar.umd.js +60 -59
- package/dist/z-index-B0Vk_Mp1.js +27 -0
- package/package.json +220 -220
- package/dist/BlockPlaceholder-IOcqxTx2.js +0 -62
- package/dist/CalendarFoundryView-Ct39xn0Q.js +0 -23561
- package/dist/Checkout-CXcjQfbc.js +0 -1805
- package/dist/Event-C_0lUZvV.js +0 -3040
- package/dist/Image-DBJAfLYe.js +0 -81
- package/dist/cancel-Cq2Q8qW7.js +0 -59
- package/dist/timezones-Cq1mLtfM.js +0 -4170
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/de.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/es.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/fr.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/id.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/it.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/ja.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/ko.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/nl.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/pl.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/pt-br.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/tr.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/flow/zh.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/de.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/es.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/fr.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/id.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/it.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/ja.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/ko.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/nl.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/pl.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/pt-br.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/tr.js +0 -0
- /package/dist/locales/{4.2.2 → 4.2.3}/main/zh.js +0 -0
package/dist/api/types.d.ts
CHANGED
|
@@ -1,528 +1,528 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Types for MicDrop Public Checkout API
|
|
3
|
-
*
|
|
4
|
-
* These types define the shape of API requests and responses
|
|
5
|
-
* for the public checkout flow (no authentication required).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { EventId, SeriesId } from '@getmicdrop/svelte-components';
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// Payment & Orders
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
export interface PaymentIntentRequest {
|
|
15
|
-
IP?: string;
|
|
16
|
-
productQuantities: Record<string | number, number>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PaymentIntentResponse {
|
|
20
|
-
client_secret: string;
|
|
21
|
-
// The residual the buyer is charged via Stripe, in int cents (net of any
|
|
22
|
-
// applied gift card). This is the field the checkout Total keys off. The
|
|
23
|
-
// orders-service response has NO `amount` key — an earlier `amount` here was
|
|
24
|
-
// never populated, so Total rendered $0.00 on every paid order.
|
|
25
|
-
stripe_amount?: number;
|
|
26
|
-
amount_total: number;
|
|
27
|
-
subtotal?: number;
|
|
28
|
-
tax?: number;
|
|
29
|
-
tax_amount_exclusive?: number;
|
|
30
|
-
service_fee?: number;
|
|
31
|
-
// The buyer's SECOND fee rail (MIC-1760) — card processing, grossed up and
|
|
32
|
-
// passed through at cost, in int cents. orders-service reports it separately
|
|
33
|
-
// from `service_fee` and folds it into `stripe_amount`. The PUBLIC receipt
|
|
34
|
-
// merges the two into one "Service fees" row (Gus, 2026-08-16), which is also
|
|
35
|
-
// what the pre-server estimate (`estimateBuyerFee`) has always shown; leaving
|
|
36
|
-
// it unread made the priced total exceed the rows on screen by this amount.
|
|
37
|
-
card_processing?: number;
|
|
38
|
-
discount?: number;
|
|
39
|
-
gift_card_amount?: number;
|
|
40
|
-
gift_card_code?: string;
|
|
41
|
-
stripe_publishable_key?: string;
|
|
42
|
-
// ISO-4217 currency (Stripe returns it lowercase). Feeds the checkout totals.
|
|
43
|
-
currency?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface CompleteReservationResponse {
|
|
47
|
-
success: boolean;
|
|
48
|
-
message?: string;
|
|
49
|
-
error?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface CancelReservationResponse {
|
|
53
|
-
success: boolean;
|
|
54
|
-
message?: string;
|
|
55
|
-
error?: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface CreateOrderRequest {
|
|
59
|
-
eventId: string | number;
|
|
60
|
-
promoCode?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface CreateOrderResponse {
|
|
64
|
-
uuid: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface ValidatePaymentRequest {
|
|
68
|
-
id: string;
|
|
69
|
-
paymentIntentId: string;
|
|
70
|
-
tickets: Record<string | number, number>;
|
|
71
|
-
firstName: string;
|
|
72
|
-
lastName: string;
|
|
73
|
-
email: string;
|
|
74
|
-
/** Buyer phone collected at checkout (MIC-1705). Persisted on the order. */
|
|
75
|
-
phone?: string;
|
|
76
|
-
/** Answer to the venue's custom checkout question (MIC-1705). */
|
|
77
|
-
questionAnswer?: string;
|
|
78
|
-
paymentMethod: string;
|
|
79
|
-
mailingList?: boolean;
|
|
80
|
-
saleType?: string;
|
|
81
|
-
attendees?: AttendeeInfo[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface AttendeeInfo {
|
|
85
|
-
ticketId: string | number;
|
|
86
|
-
firstName: string;
|
|
87
|
-
lastName: string;
|
|
88
|
-
email: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface ValidatePaymentResponse {
|
|
92
|
-
success: boolean;
|
|
93
|
-
status: string;
|
|
94
|
-
orderUUID?: string;
|
|
95
|
-
error?: string;
|
|
96
|
-
/**
|
|
97
|
-
* Fail-closed FLOOR fields. When the event is canceled/postponed between
|
|
98
|
-
* cart-creation and finalize, the backend gate refuses to capture the charge
|
|
99
|
-
* and sets one of these (alongside `success: false`). Either flag means the
|
|
100
|
-
* buyer was NOT charged; the checkout raises the charge-aware
|
|
101
|
-
* EventUnavailableModal instead of navigating to success. Optional because
|
|
102
|
-
* they are only present on the rejected-finalize path.
|
|
103
|
-
*/
|
|
104
|
-
eventCanceled?: boolean;
|
|
105
|
-
eventPostponed?: boolean;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ============================================================================
|
|
109
|
-
// Session Management
|
|
110
|
-
// ============================================================================
|
|
111
|
-
|
|
112
|
-
export interface ExtendSessionRequest {
|
|
113
|
-
orderUuid: string;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export interface ExtendSessionResponse {
|
|
117
|
-
success: boolean;
|
|
118
|
-
newExpiryTime?: string;
|
|
119
|
-
remainingExtensions?: number;
|
|
120
|
-
error?: string;
|
|
121
|
-
/**
|
|
122
|
-
* HTTP status code from the backend on failure. Populated on non-OK
|
|
123
|
-
* responses so callers can distinguish "session already expired"
|
|
124
|
-
* (typically 410 Gone) from "max extensions reached" or generic 5xx.
|
|
125
|
-
* Undefined on network errors and on success.
|
|
126
|
-
*/
|
|
127
|
-
statusCode?: number;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface SessionStatus {
|
|
131
|
-
expiresAt?: string;
|
|
132
|
-
extensionCount?: number;
|
|
133
|
-
remainingExtensions?: number;
|
|
134
|
-
canExtend?: boolean;
|
|
135
|
-
reservationCount?: number;
|
|
136
|
-
error?: string;
|
|
137
|
-
// 404 from /orders/session/{uuid}: the cart's reservations are
|
|
138
|
-
// gone (expired or never existed). Callers polling on an interval
|
|
139
|
-
// MUST treat this as terminal and stop — see CartView.svelte.
|
|
140
|
-
notFound?: boolean;
|
|
141
|
-
// Live event status the session heartbeat used to piggyback so the public
|
|
142
|
-
// checkout could flip the buy button on cancel/postpone. As of MIC-1408 the
|
|
143
|
-
// checkout rides a dedicated per-event SSE stream (subscribeEventStatus)
|
|
144
|
-
// instead, flipping instantly rather than within ~30s — this field is no
|
|
145
|
-
// longer consumed there. One of the auth-service Event statuses
|
|
146
|
-
// (draft|live|started|ended|canceled|postponed). Absent if the lookup failed.
|
|
147
|
-
eventStatus?: string;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// ============================================================================
|
|
151
|
-
// Promo Codes
|
|
152
|
-
// ============================================================================
|
|
153
|
-
|
|
154
|
-
export interface PromoValidationResponse {
|
|
155
|
-
valid: boolean;
|
|
156
|
-
revealHiddenTickets?: boolean;
|
|
157
|
-
revealTicketIds?: number[];
|
|
158
|
-
provideDiscount?: boolean;
|
|
159
|
-
discountType?: 'percentage' | 'fixed';
|
|
160
|
-
amount?: number;
|
|
161
|
-
code?: string;
|
|
162
|
-
/**
|
|
163
|
-
* The code's ticket scope, exactly as the server sends it — `false` here plus
|
|
164
|
-
* a non-empty `applyToTicketIds` means the code covers only those types.
|
|
165
|
-
* Dropped by validatePromoCode until MIC-2575, which is why a code scoped to
|
|
166
|
-
* one type discounted every type. Read through promoTicketIdsFromValidation,
|
|
167
|
-
* never field-by-field at a call site.
|
|
168
|
-
*/
|
|
169
|
-
appliesToAllTickets?: boolean;
|
|
170
|
-
applyToTicketIds?: number[];
|
|
171
|
-
error?: string;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* RAW body of GET /api/v2/public/promo-codes/validate/{eventId}/{code}.
|
|
176
|
-
*
|
|
177
|
-
* The live endpoint reports the discount magnitude as `discount` and the code
|
|
178
|
-
* as `name` — NOT `amount`/`code`. validatePromoCode normalises this into the
|
|
179
|
-
* client-facing PromoValidationResponse (amount/code) so callers read one shape.
|
|
180
|
-
* The legacy `amount`/`code` keys stay optional here so an older payload (or a
|
|
181
|
-
* mocked one) still maps through the same fallback. Verified 2026-07-11 against
|
|
182
|
-
* two live promos (seeded GUARD20PCT + pre-existing EARLY20).
|
|
183
|
-
*/
|
|
184
|
-
export interface RawPromoValidationBody {
|
|
185
|
-
valid?: boolean;
|
|
186
|
-
revealHiddenTickets?: boolean;
|
|
187
|
-
revealTicketIds?: number[];
|
|
188
|
-
provideDiscount?: boolean;
|
|
189
|
-
discountType?: 'percentage' | 'fixed';
|
|
190
|
-
/** Discount magnitude — real server field. */
|
|
191
|
-
discount?: number;
|
|
192
|
-
/** Legacy/mocked magnitude field — fallback only. */
|
|
193
|
-
amount?: number;
|
|
194
|
-
/** Promo code — real server field. */
|
|
195
|
-
name?: string;
|
|
196
|
-
/** Legacy/mocked code field — fallback only. */
|
|
197
|
-
code?: string;
|
|
198
|
-
appliesToAllTickets?: boolean;
|
|
199
|
-
applyToTicketIds?: number[];
|
|
200
|
-
isGlobal?: boolean;
|
|
201
|
-
ticketLimit?: number;
|
|
202
|
-
error?: string;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export interface HasPromoCodesResponse {
|
|
206
|
-
hasPromoCodes: boolean;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// ============================================================================
|
|
210
|
-
// Orders
|
|
211
|
-
// ============================================================================
|
|
212
|
-
|
|
213
|
-
export interface Order {
|
|
214
|
-
uuid: string;
|
|
215
|
-
id?: number;
|
|
216
|
-
customerEmail: string;
|
|
217
|
-
customerFirstName?: string;
|
|
218
|
-
customerLastName?: string;
|
|
219
|
-
status: string;
|
|
220
|
-
totalAmount: number;
|
|
221
|
-
subtotal?: number;
|
|
222
|
-
serviceFeesAmount: number;
|
|
223
|
-
taxAmount: number;
|
|
224
|
-
discount?: number;
|
|
225
|
-
paymentIntentId?: string;
|
|
226
|
-
paymentMethod?: string;
|
|
227
|
-
purchasedTickets: PurchasedTicket[];
|
|
228
|
-
createdAt?: string;
|
|
229
|
-
updatedAt?: string;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export interface PurchasedTicket {
|
|
233
|
-
uuid: string;
|
|
234
|
-
id?: number;
|
|
235
|
-
ticketNumber?: string;
|
|
236
|
-
orderId?: string | number;
|
|
237
|
-
attendeeFirstName?: string;
|
|
238
|
-
attendeeLastName?: string;
|
|
239
|
-
attendeeEmail?: string;
|
|
240
|
-
ticketName: string;
|
|
241
|
-
ticketTypeId?: number;
|
|
242
|
-
purchasePrice: number;
|
|
243
|
-
status?: string;
|
|
244
|
-
checkedIn?: boolean;
|
|
245
|
-
checkedInAt?: string;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// ============================================================================
|
|
249
|
-
// Events
|
|
250
|
-
// ============================================================================
|
|
251
|
-
|
|
252
|
-
export interface Event {
|
|
253
|
-
eventID: number;
|
|
254
|
-
id?: number;
|
|
255
|
-
name: string;
|
|
256
|
-
title?: string;
|
|
257
|
-
slug?: string;
|
|
258
|
-
description?: string;
|
|
259
|
-
date: string;
|
|
260
|
-
startDateTime?: string;
|
|
261
|
-
endDateTime?: string;
|
|
262
|
-
doorsOpenTime?: string;
|
|
263
|
-
timezone?: string;
|
|
264
|
-
venueId?: number;
|
|
265
|
-
venueName?: string;
|
|
266
|
-
venueAddress?: string;
|
|
267
|
-
location?: string;
|
|
268
|
-
imageUrl?: string;
|
|
269
|
-
imageURL?: string;
|
|
270
|
-
status?: string;
|
|
271
|
-
isPublished?: boolean;
|
|
272
|
-
isCancelled?: boolean;
|
|
273
|
-
availableTickets?: AvailableTicket[];
|
|
274
|
-
ticketsAvailable?: number;
|
|
275
|
-
ticketsSold?: number;
|
|
276
|
-
minPrice?: number;
|
|
277
|
-
maxPrice?: number;
|
|
278
|
-
ctaText?: string;
|
|
279
|
-
ctaState?: 'available' | 'sold_out' | 'coming_soon' | 'ended';
|
|
280
|
-
showPerformers?: boolean;
|
|
281
|
-
eventSeriesId?: number;
|
|
282
|
-
seriesInstanceNumber?: number;
|
|
283
|
-
// ── Passthrough seams (events convergence) ─────────────────────────────
|
|
284
|
-
// Carried verbatim from the wire by parseEvent so view-shape projections
|
|
285
|
-
// (utils/event-transform.js, public-calendar-flow/transform.ts) compose the
|
|
286
|
-
// canonical instead of reading wire fields directly. The object-valued
|
|
287
|
-
// fields are intentionally raw (see composition note in
|
|
288
|
-
// api/transformers/event.ts) — their consumers own the wire variance.
|
|
289
|
-
timeZone?: string;
|
|
290
|
-
/**
|
|
291
|
-
* The operator's sales dial — effective on public payloads (MIC-2455).
|
|
292
|
-
* `computeCtaState` refuses on `paused` / `ended` / `sold_out` and leaves
|
|
293
|
-
* `not_started` to the sale-window logic.
|
|
294
|
-
*/
|
|
295
|
-
salesStatus?: string;
|
|
296
|
-
eventSummary?: string;
|
|
297
|
-
password?: string;
|
|
298
|
-
hasPassword?: boolean;
|
|
299
|
-
disclaimer?: string;
|
|
300
|
-
ticketType?: number;
|
|
301
|
-
eventTicketingType?: number;
|
|
302
|
-
ageRestriction?: number;
|
|
303
|
-
displayAgeRestriction?: boolean;
|
|
304
|
-
displayStartTime?: boolean;
|
|
305
|
-
displayEndTime?: boolean;
|
|
306
|
-
displayDoorsTime?: boolean;
|
|
307
|
-
collectionId?: number;
|
|
308
|
-
ticketsRemaining?: number;
|
|
309
|
-
ticketsTotal?: number;
|
|
310
|
-
hasHiddenTickets?: boolean;
|
|
311
|
-
stage?: { name?: string } | null;
|
|
312
|
-
stageName?: string;
|
|
313
|
-
// Widget-filter dimensions on the public month feeds (saved-widget engine):
|
|
314
|
-
// stage/category/performer/collection data the embed adapts onto the SC
|
|
315
|
-
// FilterableEvent view (lib/widget-filters.js).
|
|
316
|
-
stageId?: number;
|
|
317
|
-
eventCategoryTypes?: number[] | null;
|
|
318
|
-
publicPerformers?: Array<{
|
|
319
|
-
id?: number;
|
|
320
|
-
displayName?: string;
|
|
321
|
-
image?: string;
|
|
322
|
-
}> | null;
|
|
323
|
-
collectionIds?: number[] | null;
|
|
324
|
-
venue?: Record<string, any>;
|
|
325
|
-
performers?: Record<string, any>[];
|
|
326
|
-
faqs?: Record<string, any>[];
|
|
327
|
-
showtimes?: Record<string, any>[];
|
|
328
|
-
purchasedTickets?: Record<string, any>[];
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export interface AvailableTicket {
|
|
332
|
-
id: number;
|
|
333
|
-
name: string;
|
|
334
|
-
description?: string;
|
|
335
|
-
price: number;
|
|
336
|
-
quantity: number;
|
|
337
|
-
quantitySold?: number;
|
|
338
|
-
quantityAvailable?: number;
|
|
339
|
-
minPerOrder?: number;
|
|
340
|
-
maxPerOrder?: number;
|
|
341
|
-
saleStartDate?: string;
|
|
342
|
-
saleEndDate?: string;
|
|
343
|
-
isHidden?: boolean;
|
|
344
|
-
revealWithPromoCode?: boolean;
|
|
345
|
-
ticketType?: number; // 0 = GA, 1 = assigned
|
|
346
|
-
sectionId?: number;
|
|
347
|
-
sortOrder?: number;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
export interface EventPerformersResponse {
|
|
351
|
-
performers: Performer[];
|
|
352
|
-
showPerformers: boolean;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export interface Performer {
|
|
356
|
-
id: number;
|
|
357
|
-
displayName: string;
|
|
358
|
-
avatar?: string;
|
|
359
|
-
order?: number;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// ============================================================================
|
|
363
|
-
// Venues
|
|
364
|
-
// ============================================================================
|
|
365
|
-
|
|
366
|
-
export interface Venue {
|
|
367
|
-
id: number;
|
|
368
|
-
name: string;
|
|
369
|
-
slug?: string;
|
|
370
|
-
address?: string;
|
|
371
|
-
googleLocationNameCache?: string;
|
|
372
|
-
city?: string;
|
|
373
|
-
state?: string;
|
|
374
|
-
zipCode?: string;
|
|
375
|
-
country?: string;
|
|
376
|
-
timezone?: string;
|
|
377
|
-
logoUrl?: string;
|
|
378
|
-
serviceFeePercentage?: number;
|
|
379
|
-
serviceFeeCents?: number;
|
|
380
|
-
/** True = the venue absorbs the service fee; false/absent = the buyer pays it. */
|
|
381
|
-
absorbServiceFee?: boolean;
|
|
382
|
-
taxPercentage?: number;
|
|
383
|
-
organizationId?: number;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// ============================================================================
|
|
387
|
-
// Series
|
|
388
|
-
// ============================================================================
|
|
389
|
-
|
|
390
|
-
export interface SeriesOccurrence {
|
|
391
|
-
eventId: EventId;
|
|
392
|
-
date: string;
|
|
393
|
-
startDateTime: string;
|
|
394
|
-
endDateTime?: string;
|
|
395
|
-
instanceNumber: number;
|
|
396
|
-
status: string;
|
|
397
|
-
ticketsAvailable?: number;
|
|
398
|
-
ctaState?: string;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export interface SeriesOccurrencesResponse {
|
|
402
|
-
seriesId: SeriesId;
|
|
403
|
-
occurrences: SeriesOccurrence[];
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// ============================================================================
|
|
407
|
-
// Series Page
|
|
408
|
-
// ============================================================================
|
|
409
|
-
|
|
410
|
-
export interface SeriesPageData {
|
|
411
|
-
id: number;
|
|
412
|
-
title: string;
|
|
413
|
-
description: string;
|
|
414
|
-
eventSummary?: string;
|
|
415
|
-
image?: string;
|
|
416
|
-
timeZone: string;
|
|
417
|
-
venue: {
|
|
418
|
-
id: number;
|
|
419
|
-
name: string;
|
|
420
|
-
location?: string;
|
|
421
|
-
googleLocationNameCache?: string;
|
|
422
|
-
faq?: Array<{ question: string; answer: string }> | string;
|
|
423
|
-
disclaimer?: string;
|
|
424
|
-
};
|
|
425
|
-
performers: Array<{
|
|
426
|
-
displayName: string;
|
|
427
|
-
firstName?: string;
|
|
428
|
-
lastName?: string;
|
|
429
|
-
profileImage?: string;
|
|
430
|
-
}>;
|
|
431
|
-
occurrences: Array<{
|
|
432
|
-
id: number;
|
|
433
|
-
slug: string;
|
|
434
|
-
startDateTime: string;
|
|
435
|
-
endDateTime: string;
|
|
436
|
-
ctaState: {
|
|
437
|
-
text: string;
|
|
438
|
-
disabled: boolean;
|
|
439
|
-
reason?: string;
|
|
440
|
-
};
|
|
441
|
-
/**
|
|
442
|
-
* The occurrence's OWN location. The backend emits this ONLY when the
|
|
443
|
-
* occurrence has been moved off the series master venue/stage, so
|
|
444
|
-
* presence === "this showtime is not where the rest of the series is".
|
|
445
|
-
* Absent for every ordinary occurrence.
|
|
446
|
-
*/
|
|
447
|
-
venue?: {
|
|
448
|
-
id: number;
|
|
449
|
-
name: string;
|
|
450
|
-
address?: string;
|
|
451
|
-
city?: string;
|
|
452
|
-
state?: string;
|
|
453
|
-
googleLocationNameCache?: string;
|
|
454
|
-
stageName?: string;
|
|
455
|
-
};
|
|
456
|
-
}>;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// ============================================================================
|
|
460
|
-
// Entity resolution (type-agnostic public id → concrete entity)
|
|
461
|
-
// ============================================================================
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Response shape of `/api/v2/public/resolve/{id}`. The embed deep-link is
|
|
465
|
-
* type-agnostic (`#{id}-{slug}`), so the backend resolves which kind of entity
|
|
466
|
-
* the id points at; `data` is the corresponding event / series / collection
|
|
467
|
-
* payload (same shape the dedicated fetchers return for that type).
|
|
468
|
-
*/
|
|
469
|
-
export interface ResolvedEntity {
|
|
470
|
-
type: 'event' | 'series' | 'collection';
|
|
471
|
-
id: string | number;
|
|
472
|
-
title?: string;
|
|
473
|
-
data: any;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// ============================================================================
|
|
477
|
-
// Public Collection
|
|
478
|
-
// ============================================================================
|
|
479
|
-
|
|
480
|
-
export interface PublicCollectionData {
|
|
481
|
-
id: number;
|
|
482
|
-
collectionTitle: string;
|
|
483
|
-
summary?: string;
|
|
484
|
-
description?: string;
|
|
485
|
-
coverImage?: string;
|
|
486
|
-
events: Array<{
|
|
487
|
-
id: number;
|
|
488
|
-
title: string;
|
|
489
|
-
slug?: string;
|
|
490
|
-
startDateTime?: string;
|
|
491
|
-
endDateTime?: string;
|
|
492
|
-
image?: string;
|
|
493
|
-
status?: string;
|
|
494
|
-
venue?: { name: string };
|
|
495
|
-
minPrice?: number;
|
|
496
|
-
}>;
|
|
497
|
-
// Password-gate variant: a protected collection responds with a gate signal
|
|
498
|
-
// instead of the collection body (either `passwordRequired: true` or an
|
|
499
|
-
// `error.code === 'PASSWORD_REQUIRED'`). Modelled here as optional wire
|
|
500
|
-
// fields so the view can read them without an `as any` escape.
|
|
501
|
-
passwordRequired?: boolean;
|
|
502
|
-
error?: { code?: string };
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// ============================================================================
|
|
506
|
-
// API Configuration
|
|
507
|
-
// ============================================================================
|
|
508
|
-
|
|
509
|
-
export interface ApiConfig {
|
|
510
|
-
baseUrl?: string;
|
|
511
|
-
timeout?: number;
|
|
512
|
-
/** Number of additional attempts after the first try (default: 2 = 3 total tries). */
|
|
513
|
-
retries?: number;
|
|
514
|
-
/** Base delay before the first retry; doubles each attempt (default: 500ms). */
|
|
515
|
-
retryDelay?: number;
|
|
516
|
-
onError?: (_error: Error) => void;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// ============================================================================
|
|
520
|
-
// Generic API Response
|
|
521
|
-
// ============================================================================
|
|
522
|
-
|
|
523
|
-
export interface ApiResponse<T> {
|
|
524
|
-
success: boolean;
|
|
525
|
-
data?: T;
|
|
526
|
-
error?: string;
|
|
527
|
-
statusCode?: number;
|
|
528
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* API Types for MicDrop Public Checkout API
|
|
3
|
+
*
|
|
4
|
+
* These types define the shape of API requests and responses
|
|
5
|
+
* for the public checkout flow (no authentication required).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { EventId, SeriesId } from '@getmicdrop/svelte-components';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Payment & Orders
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export interface PaymentIntentRequest {
|
|
15
|
+
IP?: string;
|
|
16
|
+
productQuantities: Record<string | number, number>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PaymentIntentResponse {
|
|
20
|
+
client_secret: string;
|
|
21
|
+
// The residual the buyer is charged via Stripe, in int cents (net of any
|
|
22
|
+
// applied gift card). This is the field the checkout Total keys off. The
|
|
23
|
+
// orders-service response has NO `amount` key — an earlier `amount` here was
|
|
24
|
+
// never populated, so Total rendered $0.00 on every paid order.
|
|
25
|
+
stripe_amount?: number;
|
|
26
|
+
amount_total: number;
|
|
27
|
+
subtotal?: number;
|
|
28
|
+
tax?: number;
|
|
29
|
+
tax_amount_exclusive?: number;
|
|
30
|
+
service_fee?: number;
|
|
31
|
+
// The buyer's SECOND fee rail (MIC-1760) — card processing, grossed up and
|
|
32
|
+
// passed through at cost, in int cents. orders-service reports it separately
|
|
33
|
+
// from `service_fee` and folds it into `stripe_amount`. The PUBLIC receipt
|
|
34
|
+
// merges the two into one "Service fees" row (Gus, 2026-08-16), which is also
|
|
35
|
+
// what the pre-server estimate (`estimateBuyerFee`) has always shown; leaving
|
|
36
|
+
// it unread made the priced total exceed the rows on screen by this amount.
|
|
37
|
+
card_processing?: number;
|
|
38
|
+
discount?: number;
|
|
39
|
+
gift_card_amount?: number;
|
|
40
|
+
gift_card_code?: string;
|
|
41
|
+
stripe_publishable_key?: string;
|
|
42
|
+
// ISO-4217 currency (Stripe returns it lowercase). Feeds the checkout totals.
|
|
43
|
+
currency?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CompleteReservationResponse {
|
|
47
|
+
success: boolean;
|
|
48
|
+
message?: string;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface CancelReservationResponse {
|
|
53
|
+
success: boolean;
|
|
54
|
+
message?: string;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface CreateOrderRequest {
|
|
59
|
+
eventId: string | number;
|
|
60
|
+
promoCode?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface CreateOrderResponse {
|
|
64
|
+
uuid: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ValidatePaymentRequest {
|
|
68
|
+
id: string;
|
|
69
|
+
paymentIntentId: string;
|
|
70
|
+
tickets: Record<string | number, number>;
|
|
71
|
+
firstName: string;
|
|
72
|
+
lastName: string;
|
|
73
|
+
email: string;
|
|
74
|
+
/** Buyer phone collected at checkout (MIC-1705). Persisted on the order. */
|
|
75
|
+
phone?: string;
|
|
76
|
+
/** Answer to the venue's custom checkout question (MIC-1705). */
|
|
77
|
+
questionAnswer?: string;
|
|
78
|
+
paymentMethod: string;
|
|
79
|
+
mailingList?: boolean;
|
|
80
|
+
saleType?: string;
|
|
81
|
+
attendees?: AttendeeInfo[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface AttendeeInfo {
|
|
85
|
+
ticketId: string | number;
|
|
86
|
+
firstName: string;
|
|
87
|
+
lastName: string;
|
|
88
|
+
email: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ValidatePaymentResponse {
|
|
92
|
+
success: boolean;
|
|
93
|
+
status: string;
|
|
94
|
+
orderUUID?: string;
|
|
95
|
+
error?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Fail-closed FLOOR fields. When the event is canceled/postponed between
|
|
98
|
+
* cart-creation and finalize, the backend gate refuses to capture the charge
|
|
99
|
+
* and sets one of these (alongside `success: false`). Either flag means the
|
|
100
|
+
* buyer was NOT charged; the checkout raises the charge-aware
|
|
101
|
+
* EventUnavailableModal instead of navigating to success. Optional because
|
|
102
|
+
* they are only present on the rejected-finalize path.
|
|
103
|
+
*/
|
|
104
|
+
eventCanceled?: boolean;
|
|
105
|
+
eventPostponed?: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Session Management
|
|
110
|
+
// ============================================================================
|
|
111
|
+
|
|
112
|
+
export interface ExtendSessionRequest {
|
|
113
|
+
orderUuid: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface ExtendSessionResponse {
|
|
117
|
+
success: boolean;
|
|
118
|
+
newExpiryTime?: string;
|
|
119
|
+
remainingExtensions?: number;
|
|
120
|
+
error?: string;
|
|
121
|
+
/**
|
|
122
|
+
* HTTP status code from the backend on failure. Populated on non-OK
|
|
123
|
+
* responses so callers can distinguish "session already expired"
|
|
124
|
+
* (typically 410 Gone) from "max extensions reached" or generic 5xx.
|
|
125
|
+
* Undefined on network errors and on success.
|
|
126
|
+
*/
|
|
127
|
+
statusCode?: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface SessionStatus {
|
|
131
|
+
expiresAt?: string;
|
|
132
|
+
extensionCount?: number;
|
|
133
|
+
remainingExtensions?: number;
|
|
134
|
+
canExtend?: boolean;
|
|
135
|
+
reservationCount?: number;
|
|
136
|
+
error?: string;
|
|
137
|
+
// 404 from /orders/session/{uuid}: the cart's reservations are
|
|
138
|
+
// gone (expired or never existed). Callers polling on an interval
|
|
139
|
+
// MUST treat this as terminal and stop — see CartView.svelte.
|
|
140
|
+
notFound?: boolean;
|
|
141
|
+
// Live event status the session heartbeat used to piggyback so the public
|
|
142
|
+
// checkout could flip the buy button on cancel/postpone. As of MIC-1408 the
|
|
143
|
+
// checkout rides a dedicated per-event SSE stream (subscribeEventStatus)
|
|
144
|
+
// instead, flipping instantly rather than within ~30s — this field is no
|
|
145
|
+
// longer consumed there. One of the auth-service Event statuses
|
|
146
|
+
// (draft|live|started|ended|canceled|postponed). Absent if the lookup failed.
|
|
147
|
+
eventStatus?: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Promo Codes
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
export interface PromoValidationResponse {
|
|
155
|
+
valid: boolean;
|
|
156
|
+
revealHiddenTickets?: boolean;
|
|
157
|
+
revealTicketIds?: number[];
|
|
158
|
+
provideDiscount?: boolean;
|
|
159
|
+
discountType?: 'percentage' | 'fixed';
|
|
160
|
+
amount?: number;
|
|
161
|
+
code?: string;
|
|
162
|
+
/**
|
|
163
|
+
* The code's ticket scope, exactly as the server sends it — `false` here plus
|
|
164
|
+
* a non-empty `applyToTicketIds` means the code covers only those types.
|
|
165
|
+
* Dropped by validatePromoCode until MIC-2575, which is why a code scoped to
|
|
166
|
+
* one type discounted every type. Read through promoTicketIdsFromValidation,
|
|
167
|
+
* never field-by-field at a call site.
|
|
168
|
+
*/
|
|
169
|
+
appliesToAllTickets?: boolean;
|
|
170
|
+
applyToTicketIds?: number[];
|
|
171
|
+
error?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* RAW body of GET /api/v2/public/promo-codes/validate/{eventId}/{code}.
|
|
176
|
+
*
|
|
177
|
+
* The live endpoint reports the discount magnitude as `discount` and the code
|
|
178
|
+
* as `name` — NOT `amount`/`code`. validatePromoCode normalises this into the
|
|
179
|
+
* client-facing PromoValidationResponse (amount/code) so callers read one shape.
|
|
180
|
+
* The legacy `amount`/`code` keys stay optional here so an older payload (or a
|
|
181
|
+
* mocked one) still maps through the same fallback. Verified 2026-07-11 against
|
|
182
|
+
* two live promos (seeded GUARD20PCT + pre-existing EARLY20).
|
|
183
|
+
*/
|
|
184
|
+
export interface RawPromoValidationBody {
|
|
185
|
+
valid?: boolean;
|
|
186
|
+
revealHiddenTickets?: boolean;
|
|
187
|
+
revealTicketIds?: number[];
|
|
188
|
+
provideDiscount?: boolean;
|
|
189
|
+
discountType?: 'percentage' | 'fixed';
|
|
190
|
+
/** Discount magnitude — real server field. */
|
|
191
|
+
discount?: number;
|
|
192
|
+
/** Legacy/mocked magnitude field — fallback only. */
|
|
193
|
+
amount?: number;
|
|
194
|
+
/** Promo code — real server field. */
|
|
195
|
+
name?: string;
|
|
196
|
+
/** Legacy/mocked code field — fallback only. */
|
|
197
|
+
code?: string;
|
|
198
|
+
appliesToAllTickets?: boolean;
|
|
199
|
+
applyToTicketIds?: number[];
|
|
200
|
+
isGlobal?: boolean;
|
|
201
|
+
ticketLimit?: number;
|
|
202
|
+
error?: string;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface HasPromoCodesResponse {
|
|
206
|
+
hasPromoCodes: boolean;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// Orders
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
export interface Order {
|
|
214
|
+
uuid: string;
|
|
215
|
+
id?: number;
|
|
216
|
+
customerEmail: string;
|
|
217
|
+
customerFirstName?: string;
|
|
218
|
+
customerLastName?: string;
|
|
219
|
+
status: string;
|
|
220
|
+
totalAmount: number;
|
|
221
|
+
subtotal?: number;
|
|
222
|
+
serviceFeesAmount: number;
|
|
223
|
+
taxAmount: number;
|
|
224
|
+
discount?: number;
|
|
225
|
+
paymentIntentId?: string;
|
|
226
|
+
paymentMethod?: string;
|
|
227
|
+
purchasedTickets: PurchasedTicket[];
|
|
228
|
+
createdAt?: string;
|
|
229
|
+
updatedAt?: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface PurchasedTicket {
|
|
233
|
+
uuid: string;
|
|
234
|
+
id?: number;
|
|
235
|
+
ticketNumber?: string;
|
|
236
|
+
orderId?: string | number;
|
|
237
|
+
attendeeFirstName?: string;
|
|
238
|
+
attendeeLastName?: string;
|
|
239
|
+
attendeeEmail?: string;
|
|
240
|
+
ticketName: string;
|
|
241
|
+
ticketTypeId?: number;
|
|
242
|
+
purchasePrice: number;
|
|
243
|
+
status?: string;
|
|
244
|
+
checkedIn?: boolean;
|
|
245
|
+
checkedInAt?: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ============================================================================
|
|
249
|
+
// Events
|
|
250
|
+
// ============================================================================
|
|
251
|
+
|
|
252
|
+
export interface Event {
|
|
253
|
+
eventID: number;
|
|
254
|
+
id?: number;
|
|
255
|
+
name: string;
|
|
256
|
+
title?: string;
|
|
257
|
+
slug?: string;
|
|
258
|
+
description?: string;
|
|
259
|
+
date: string;
|
|
260
|
+
startDateTime?: string;
|
|
261
|
+
endDateTime?: string;
|
|
262
|
+
doorsOpenTime?: string;
|
|
263
|
+
timezone?: string;
|
|
264
|
+
venueId?: number;
|
|
265
|
+
venueName?: string;
|
|
266
|
+
venueAddress?: string;
|
|
267
|
+
location?: string;
|
|
268
|
+
imageUrl?: string;
|
|
269
|
+
imageURL?: string;
|
|
270
|
+
status?: string;
|
|
271
|
+
isPublished?: boolean;
|
|
272
|
+
isCancelled?: boolean;
|
|
273
|
+
availableTickets?: AvailableTicket[];
|
|
274
|
+
ticketsAvailable?: number;
|
|
275
|
+
ticketsSold?: number;
|
|
276
|
+
minPrice?: number;
|
|
277
|
+
maxPrice?: number;
|
|
278
|
+
ctaText?: string;
|
|
279
|
+
ctaState?: 'available' | 'sold_out' | 'coming_soon' | 'ended';
|
|
280
|
+
showPerformers?: boolean;
|
|
281
|
+
eventSeriesId?: number;
|
|
282
|
+
seriesInstanceNumber?: number;
|
|
283
|
+
// ── Passthrough seams (events convergence) ─────────────────────────────
|
|
284
|
+
// Carried verbatim from the wire by parseEvent so view-shape projections
|
|
285
|
+
// (utils/event-transform.js, public-calendar-flow/transform.ts) compose the
|
|
286
|
+
// canonical instead of reading wire fields directly. The object-valued
|
|
287
|
+
// fields are intentionally raw (see composition note in
|
|
288
|
+
// api/transformers/event.ts) — their consumers own the wire variance.
|
|
289
|
+
timeZone?: string;
|
|
290
|
+
/**
|
|
291
|
+
* The operator's sales dial — effective on public payloads (MIC-2455).
|
|
292
|
+
* `computeCtaState` refuses on `paused` / `ended` / `sold_out` and leaves
|
|
293
|
+
* `not_started` to the sale-window logic.
|
|
294
|
+
*/
|
|
295
|
+
salesStatus?: string;
|
|
296
|
+
eventSummary?: string;
|
|
297
|
+
password?: string;
|
|
298
|
+
hasPassword?: boolean;
|
|
299
|
+
disclaimer?: string;
|
|
300
|
+
ticketType?: number;
|
|
301
|
+
eventTicketingType?: number;
|
|
302
|
+
ageRestriction?: number;
|
|
303
|
+
displayAgeRestriction?: boolean;
|
|
304
|
+
displayStartTime?: boolean;
|
|
305
|
+
displayEndTime?: boolean;
|
|
306
|
+
displayDoorsTime?: boolean;
|
|
307
|
+
collectionId?: number;
|
|
308
|
+
ticketsRemaining?: number;
|
|
309
|
+
ticketsTotal?: number;
|
|
310
|
+
hasHiddenTickets?: boolean;
|
|
311
|
+
stage?: { name?: string } | null;
|
|
312
|
+
stageName?: string;
|
|
313
|
+
// Widget-filter dimensions on the public month feeds (saved-widget engine):
|
|
314
|
+
// stage/category/performer/collection data the embed adapts onto the SC
|
|
315
|
+
// FilterableEvent view (lib/widget-filters.js).
|
|
316
|
+
stageId?: number;
|
|
317
|
+
eventCategoryTypes?: number[] | null;
|
|
318
|
+
publicPerformers?: Array<{
|
|
319
|
+
id?: number;
|
|
320
|
+
displayName?: string;
|
|
321
|
+
image?: string;
|
|
322
|
+
}> | null;
|
|
323
|
+
collectionIds?: number[] | null;
|
|
324
|
+
venue?: Record<string, any>;
|
|
325
|
+
performers?: Record<string, any>[];
|
|
326
|
+
faqs?: Record<string, any>[];
|
|
327
|
+
showtimes?: Record<string, any>[];
|
|
328
|
+
purchasedTickets?: Record<string, any>[];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface AvailableTicket {
|
|
332
|
+
id: number;
|
|
333
|
+
name: string;
|
|
334
|
+
description?: string;
|
|
335
|
+
price: number;
|
|
336
|
+
quantity: number;
|
|
337
|
+
quantitySold?: number;
|
|
338
|
+
quantityAvailable?: number;
|
|
339
|
+
minPerOrder?: number;
|
|
340
|
+
maxPerOrder?: number;
|
|
341
|
+
saleStartDate?: string;
|
|
342
|
+
saleEndDate?: string;
|
|
343
|
+
isHidden?: boolean;
|
|
344
|
+
revealWithPromoCode?: boolean;
|
|
345
|
+
ticketType?: number; // 0 = GA, 1 = assigned
|
|
346
|
+
sectionId?: number;
|
|
347
|
+
sortOrder?: number;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export interface EventPerformersResponse {
|
|
351
|
+
performers: Performer[];
|
|
352
|
+
showPerformers: boolean;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface Performer {
|
|
356
|
+
id: number;
|
|
357
|
+
displayName: string;
|
|
358
|
+
avatar?: string;
|
|
359
|
+
order?: number;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ============================================================================
|
|
363
|
+
// Venues
|
|
364
|
+
// ============================================================================
|
|
365
|
+
|
|
366
|
+
export interface Venue {
|
|
367
|
+
id: number;
|
|
368
|
+
name: string;
|
|
369
|
+
slug?: string;
|
|
370
|
+
address?: string;
|
|
371
|
+
googleLocationNameCache?: string;
|
|
372
|
+
city?: string;
|
|
373
|
+
state?: string;
|
|
374
|
+
zipCode?: string;
|
|
375
|
+
country?: string;
|
|
376
|
+
timezone?: string;
|
|
377
|
+
logoUrl?: string;
|
|
378
|
+
serviceFeePercentage?: number;
|
|
379
|
+
serviceFeeCents?: number;
|
|
380
|
+
/** True = the venue absorbs the service fee; false/absent = the buyer pays it. */
|
|
381
|
+
absorbServiceFee?: boolean;
|
|
382
|
+
taxPercentage?: number;
|
|
383
|
+
organizationId?: number;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// ============================================================================
|
|
387
|
+
// Series
|
|
388
|
+
// ============================================================================
|
|
389
|
+
|
|
390
|
+
export interface SeriesOccurrence {
|
|
391
|
+
eventId: EventId;
|
|
392
|
+
date: string;
|
|
393
|
+
startDateTime: string;
|
|
394
|
+
endDateTime?: string;
|
|
395
|
+
instanceNumber: number;
|
|
396
|
+
status: string;
|
|
397
|
+
ticketsAvailable?: number;
|
|
398
|
+
ctaState?: string;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface SeriesOccurrencesResponse {
|
|
402
|
+
seriesId: SeriesId;
|
|
403
|
+
occurrences: SeriesOccurrence[];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ============================================================================
|
|
407
|
+
// Series Page
|
|
408
|
+
// ============================================================================
|
|
409
|
+
|
|
410
|
+
export interface SeriesPageData {
|
|
411
|
+
id: number;
|
|
412
|
+
title: string;
|
|
413
|
+
description: string;
|
|
414
|
+
eventSummary?: string;
|
|
415
|
+
image?: string;
|
|
416
|
+
timeZone: string;
|
|
417
|
+
venue: {
|
|
418
|
+
id: number;
|
|
419
|
+
name: string;
|
|
420
|
+
location?: string;
|
|
421
|
+
googleLocationNameCache?: string;
|
|
422
|
+
faq?: Array<{ question: string; answer: string }> | string;
|
|
423
|
+
disclaimer?: string;
|
|
424
|
+
};
|
|
425
|
+
performers: Array<{
|
|
426
|
+
displayName: string;
|
|
427
|
+
firstName?: string;
|
|
428
|
+
lastName?: string;
|
|
429
|
+
profileImage?: string;
|
|
430
|
+
}>;
|
|
431
|
+
occurrences: Array<{
|
|
432
|
+
id: number;
|
|
433
|
+
slug: string;
|
|
434
|
+
startDateTime: string;
|
|
435
|
+
endDateTime: string;
|
|
436
|
+
ctaState: {
|
|
437
|
+
text: string;
|
|
438
|
+
disabled: boolean;
|
|
439
|
+
reason?: string;
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* The occurrence's OWN location. The backend emits this ONLY when the
|
|
443
|
+
* occurrence has been moved off the series master venue/stage, so
|
|
444
|
+
* presence === "this showtime is not where the rest of the series is".
|
|
445
|
+
* Absent for every ordinary occurrence.
|
|
446
|
+
*/
|
|
447
|
+
venue?: {
|
|
448
|
+
id: number;
|
|
449
|
+
name: string;
|
|
450
|
+
address?: string;
|
|
451
|
+
city?: string;
|
|
452
|
+
state?: string;
|
|
453
|
+
googleLocationNameCache?: string;
|
|
454
|
+
stageName?: string;
|
|
455
|
+
};
|
|
456
|
+
}>;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Entity resolution (type-agnostic public id → concrete entity)
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Response shape of `/api/v2/public/resolve/{id}`. The embed deep-link is
|
|
465
|
+
* type-agnostic (`#{id}-{slug}`), so the backend resolves which kind of entity
|
|
466
|
+
* the id points at; `data` is the corresponding event / series / collection
|
|
467
|
+
* payload (same shape the dedicated fetchers return for that type).
|
|
468
|
+
*/
|
|
469
|
+
export interface ResolvedEntity {
|
|
470
|
+
type: 'event' | 'series' | 'collection';
|
|
471
|
+
id: string | number;
|
|
472
|
+
title?: string;
|
|
473
|
+
data: any;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ============================================================================
|
|
477
|
+
// Public Collection
|
|
478
|
+
// ============================================================================
|
|
479
|
+
|
|
480
|
+
export interface PublicCollectionData {
|
|
481
|
+
id: number;
|
|
482
|
+
collectionTitle: string;
|
|
483
|
+
summary?: string;
|
|
484
|
+
description?: string;
|
|
485
|
+
coverImage?: string;
|
|
486
|
+
events: Array<{
|
|
487
|
+
id: number;
|
|
488
|
+
title: string;
|
|
489
|
+
slug?: string;
|
|
490
|
+
startDateTime?: string;
|
|
491
|
+
endDateTime?: string;
|
|
492
|
+
image?: string;
|
|
493
|
+
status?: string;
|
|
494
|
+
venue?: { name: string };
|
|
495
|
+
minPrice?: number;
|
|
496
|
+
}>;
|
|
497
|
+
// Password-gate variant: a protected collection responds with a gate signal
|
|
498
|
+
// instead of the collection body (either `passwordRequired: true` or an
|
|
499
|
+
// `error.code === 'PASSWORD_REQUIRED'`). Modelled here as optional wire
|
|
500
|
+
// fields so the view can read them without an `as any` escape.
|
|
501
|
+
passwordRequired?: boolean;
|
|
502
|
+
error?: { code?: string };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// ============================================================================
|
|
506
|
+
// API Configuration
|
|
507
|
+
// ============================================================================
|
|
508
|
+
|
|
509
|
+
export interface ApiConfig {
|
|
510
|
+
baseUrl?: string;
|
|
511
|
+
timeout?: number;
|
|
512
|
+
/** Number of additional attempts after the first try (default: 2 = 3 total tries). */
|
|
513
|
+
retries?: number;
|
|
514
|
+
/** Base delay before the first retry; doubles each attempt (default: 500ms). */
|
|
515
|
+
retryDelay?: number;
|
|
516
|
+
onError?: (_error: Error) => void;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// Generic API Response
|
|
521
|
+
// ============================================================================
|
|
522
|
+
|
|
523
|
+
export interface ApiResponse<T> {
|
|
524
|
+
success: boolean;
|
|
525
|
+
data?: T;
|
|
526
|
+
error?: string;
|
|
527
|
+
statusCode?: number;
|
|
528
|
+
}
|