@getmicdrop/venue-calendar 4.3.1 → 4.3.2

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.
Files changed (62) hide show
  1. package/dist/api/api.cjs +1 -0
  2. package/dist/api/api.mjs +1442 -0
  3. package/dist/api/client.d.ts +157 -0
  4. package/dist/api/cta.d.ts +50 -0
  5. package/dist/api/events.d.ts +202 -0
  6. package/dist/api/gift-cards.d.ts +119 -0
  7. package/dist/api/index.d.ts +46 -0
  8. package/dist/api/orders.d.ts +193 -0
  9. package/dist/api/promo.d.ts +45 -0
  10. package/dist/api/result.d.ts +78 -0
  11. package/dist/api/route-manifest.d.ts +206 -0
  12. package/dist/api/transformers/address.d.ts +18 -0
  13. package/dist/api/transformers/cart.d.ts +34 -0
  14. package/dist/api/transformers/collection.d.ts +12 -0
  15. package/dist/api/transformers/event.d.ts +177 -0
  16. package/dist/api/transformers/faq.d.ts +40 -0
  17. package/dist/api/transformers/giftCard.d.ts +11 -0
  18. package/dist/api/transformers/index.d.ts +27 -0
  19. package/dist/api/transformers/order.d.ts +44 -0
  20. package/dist/api/transformers/performer.d.ts +8 -0
  21. package/dist/api/transformers/series.d.ts +12 -0
  22. package/dist/api/transformers/venue.d.ts +65 -0
  23. package/dist/api/types.d.ts +554 -0
  24. package/dist/api/venues.d.ts +33 -0
  25. package/dist/api/waitlist.d.ts +77 -0
  26. package/dist/seo/HostSeoController.d.ts +68 -0
  27. package/dist/seo/buildCollectionJsonLd.d.ts +8 -0
  28. package/dist/seo/buildEventJsonLd.d.ts +9 -0
  29. package/dist/seo/buildSeriesJsonLd.d.ts +6 -0
  30. package/dist/seo/helpers.d.ts +88 -0
  31. package/dist/seo/index.d.ts +10 -0
  32. package/dist/seo/seo.cjs +1 -0
  33. package/dist/seo/seo.mjs +592 -0
  34. package/dist/seo/types.d.ts +156 -0
  35. package/dist/venue-calendar.es.js +1 -1
  36. package/dist/venue-calendar.iife.js +2 -2
  37. package/dist/venue-calendar.umd.js +1 -1
  38. package/package.json +1 -1
  39. /package/dist/locales/{4.3.1 → 4.3.2}/flow/de.js +0 -0
  40. /package/dist/locales/{4.3.1 → 4.3.2}/flow/es.js +0 -0
  41. /package/dist/locales/{4.3.1 → 4.3.2}/flow/fr.js +0 -0
  42. /package/dist/locales/{4.3.1 → 4.3.2}/flow/id.js +0 -0
  43. /package/dist/locales/{4.3.1 → 4.3.2}/flow/it.js +0 -0
  44. /package/dist/locales/{4.3.1 → 4.3.2}/flow/ja.js +0 -0
  45. /package/dist/locales/{4.3.1 → 4.3.2}/flow/ko.js +0 -0
  46. /package/dist/locales/{4.3.1 → 4.3.2}/flow/nl.js +0 -0
  47. /package/dist/locales/{4.3.1 → 4.3.2}/flow/pl.js +0 -0
  48. /package/dist/locales/{4.3.1 → 4.3.2}/flow/pt-br.js +0 -0
  49. /package/dist/locales/{4.3.1 → 4.3.2}/flow/tr.js +0 -0
  50. /package/dist/locales/{4.3.1 → 4.3.2}/flow/zh.js +0 -0
  51. /package/dist/locales/{4.3.1 → 4.3.2}/main/de.js +0 -0
  52. /package/dist/locales/{4.3.1 → 4.3.2}/main/es.js +0 -0
  53. /package/dist/locales/{4.3.1 → 4.3.2}/main/fr.js +0 -0
  54. /package/dist/locales/{4.3.1 → 4.3.2}/main/id.js +0 -0
  55. /package/dist/locales/{4.3.1 → 4.3.2}/main/it.js +0 -0
  56. /package/dist/locales/{4.3.1 → 4.3.2}/main/ja.js +0 -0
  57. /package/dist/locales/{4.3.1 → 4.3.2}/main/ko.js +0 -0
  58. /package/dist/locales/{4.3.1 → 4.3.2}/main/nl.js +0 -0
  59. /package/dist/locales/{4.3.1 → 4.3.2}/main/pl.js +0 -0
  60. /package/dist/locales/{4.3.1 → 4.3.2}/main/pt-br.js +0 -0
  61. /package/dist/locales/{4.3.1 → 4.3.2}/main/tr.js +0 -0
  62. /package/dist/locales/{4.3.1 → 4.3.2}/main/zh.js +0 -0
@@ -0,0 +1,193 @@
1
+ import { PaymentIntentResponse, CompleteReservationResponse, CancelReservationResponse, CreateOrderResponse, ValidatePaymentRequest, ValidatePaymentResponse, ExtendSessionResponse, SessionStatus, Order } from './types.js';
2
+ /**
3
+ * Create a payment intent for the cart
4
+ *
5
+ * This initiates the Stripe payment flow by creating a PaymentIntent
6
+ * on the backend. The response includes the client_secret needed
7
+ * for Stripe Elements.
8
+ *
9
+ * @param cartId - The cart/order UUID
10
+ * @param quantities - Map of ticketId -> quantity
11
+ * @param donationAmounts - Map of ticketId -> donation amount in dollars (for type=2 tickets)
12
+ * @returns Payment intent data including client_secret, or null on error
13
+ */
14
+ /** The buyer, sent ONLY on the $0 finalize call. See createPaymentIntent. */
15
+ export interface FreeOrderBuyer {
16
+ firstName: string;
17
+ lastName: string;
18
+ email: string;
19
+ /**
20
+ * The venue's checkout-settings answers. The paid path persists both at
21
+ * validate-payment-intent, which a $0 order never reaches — so for a free
22
+ * order this call is the only place they can land.
23
+ */
24
+ phone?: string;
25
+ questionAnswer?: string;
26
+ mailingList?: boolean;
27
+ }
28
+ export declare function createPaymentIntent(cartId: string, quantities: Record<string | number, number>, donationAmounts?: Record<string | number, number>, buyer?: FreeOrderBuyer, uiLocale?: string): Promise<PaymentIntentResponse | null>;
29
+ /**
30
+ * Fetch an existing cart by UUID (cross-device pre-fill — §1.3).
31
+ *
32
+ * Returns the server's authoritative view of a cart so a second device
33
+ * visiting the tickets page can see the in-progress reservation it created
34
+ * on another device. Returns `null` if:
35
+ * - the cart no longer exists (404)
36
+ * - the cart belongs to a different event than `expectedEventID` (when
37
+ * supplied) — we don't want to mix carts across events
38
+ * - the cart status is no longer `reserved` / `active` (e.g. expired,
39
+ * completed, abandoned) — caller should treat the local cookie as stale
40
+ * - any network/decode failure (caller falls back to localStorage only)
41
+ *
42
+ * Returned shape matches the orders-service `GET /v2Public/cart/{uuid}`
43
+ * response: a Cart model with embedded Reservations.
44
+ */
45
+ export interface CartReservationView {
46
+ ticketID: number;
47
+ quantity: number;
48
+ priceAtReservation: number;
49
+ status: string;
50
+ }
51
+ /** One gift card already applied to the cart, as the server will describe it. */
52
+ export interface CartGiftCardView {
53
+ giftCardId: number;
54
+ /** Last four only — the server never returns the code. Display, not identity. */
55
+ maskedCode: string;
56
+ /**
57
+ * Allocated amount in DOLLARS (the wire carries cents), or null when the
58
+ * server sent nothing usable — never 0, which would understate coverage.
59
+ */
60
+ amount: number | null;
61
+ }
62
+ export interface CartView {
63
+ uuid: string;
64
+ eventID: number;
65
+ status: string;
66
+ expiresAt: string;
67
+ reservations: CartReservationView[];
68
+ giftCards: CartGiftCardView[];
69
+ }
70
+ export declare function getCartByUUID(cartUUID: string, expectedEventID?: string | number): Promise<CartView | null>;
71
+ /**
72
+ * Update cart quantities after the cart already exists.
73
+ *
74
+ * Replaces all reservations on the cart with the new quantities.
75
+ * The orders-service handler releases old reservations (returning
76
+ * inventory) and creates new ones (decrementing inventory) atomically.
77
+ *
78
+ * Use this when the user changes ticket counts AFTER the initial
79
+ * cart was created via initiateOrder. The cart UUID is preserved,
80
+ * so the timer and extension state stay intact.
81
+ *
82
+ * @returns true on success, false on failure
83
+ */
84
+ export declare function updateCartQuantities(cartId: string, quantities: Record<string | number, number>, donationAmounts?: Record<string | number, number>): Promise<boolean>;
85
+ /**
86
+ * Complete reservation after successful payment
87
+ *
88
+ * Called after Stripe confirms the payment to finalize the order
89
+ * and generate tickets.
90
+ *
91
+ * @param orderUuid - The order UUID
92
+ * @returns Success status and message
93
+ */
94
+ export declare function completeReservation(orderUuid: string): Promise<CompleteReservationResponse>;
95
+ /**
96
+ * Cancel reservation and release tickets back to inventory
97
+ *
98
+ * Called when user abandons checkout or session expires.
99
+ *
100
+ * @param orderUuid - The order UUID
101
+ * @returns Success status and message
102
+ */
103
+ export declare function cancelReservation(orderUuid: string): Promise<CancelReservationResponse>;
104
+ /**
105
+ * Request a refund for a completed order (buyer self-service).
106
+ *
107
+ * Public, login-less: the buyer reaches their tickets page from the order UUID in
108
+ * their confirmation link, so the same UUID authorizes the request. This does NOT
109
+ * move money — it flags the order (RefundRequested + an optional buyer message)
110
+ * for the venue/operator to action from their dashboard, exactly as the backend
111
+ * RequestRefund handler records it. Replaces the "email the venue" dead-end that
112
+ * was the only way to ask for a refund from the ticket page (MIC-1795).
113
+ *
114
+ * @param orderUUID - The order UUID
115
+ * @param message - Optional note to the venue (why they want a refund)
116
+ * @returns Success status, with an error message on failure
117
+ */
118
+ export declare function requestOrderRefund(orderUUID: string, message?: string): Promise<{
119
+ success: boolean;
120
+ error?: string;
121
+ }>;
122
+ /**
123
+ * Create a new order/cart
124
+ *
125
+ * This creates an empty order that can be used for checkout.
126
+ * The order UUID is used for all subsequent operations.
127
+ *
128
+ * @param eventId - The event ID
129
+ * @param promoCode - Optional promo code to apply
130
+ * @returns The order UUID, or null on error
131
+ */
132
+ export declare function createOrder(eventId: string | number, promoCode?: string): Promise<CreateOrderResponse | null>;
133
+ /**
134
+ * Get order details (public, no auth required)
135
+ *
136
+ * Fetches the order details for displaying on the success page.
137
+ *
138
+ * @param orderId - The order UUID or ID
139
+ * @returns The order details, or null on error
140
+ */
141
+ export declare function getOrder(orderId: string): Promise<Order | null>;
142
+ /**
143
+ * Validate payment intent and complete the order
144
+ *
145
+ * This is an alternative to completeReservation that accepts
146
+ * additional payment details. Used by micdrop-frontend.
147
+ *
148
+ * @param cartId - The cart/order UUID
149
+ * @param payload - Payment validation payload
150
+ * @returns Validation result
151
+ */
152
+ export declare function validatePaymentIntent(cartId: string, payload: ValidatePaymentRequest, uiLocale?: string): Promise<ValidatePaymentResponse | null>;
153
+ /**
154
+ * Extend the checkout session by 15 minutes
155
+ *
156
+ * Users get a limited number of extensions (typically 2-3).
157
+ *
158
+ * @param orderUuid - The order UUID
159
+ * @returns Extension result with new expiry time
160
+ */
161
+ export declare function extendCheckoutSession(orderUuid: string): Promise<ExtendSessionResponse>;
162
+ /**
163
+ * Get current session status including expiry time
164
+ *
165
+ * Used to display countdown timer and check if extensions are available.
166
+ *
167
+ * @param orderUuid - The order UUID
168
+ * @returns Session status including expiry time
169
+ */
170
+ export declare function getSessionStatus(orderUuid: string): Promise<SessionStatus>;
171
+ /**
172
+ * Initiate a new order (alias for createOrder)
173
+ *
174
+ * This function provides backwards compatibility with micdrop-frontend.
175
+ * It accepts the same parameters as the legacy initiateOrder function.
176
+ *
177
+ * @param cartData - Object containing eventID and optional quantities/promoCode
178
+ * @returns The order UUID, or null on error
179
+ */
180
+ export declare function initiateOrder(cartData?: {
181
+ eventID: string | number;
182
+ promoCode?: string;
183
+ quantities?: Record<string | number, number>;
184
+ }): Promise<string | null>;
185
+ /**
186
+ * Track UTM source for analytics
187
+ *
188
+ * Records the traffic source (utm_source parameter) for marketing analytics.
189
+ *
190
+ * @param venueId - The venue ID
191
+ * @returns Promise that resolves when tracking is complete
192
+ */
193
+ export declare function trackUTMSource(venueId: string | number): Promise<void>;
@@ -0,0 +1,45 @@
1
+ import { PromoValidationResponse } from './types.js';
2
+ /**
3
+ * Validate a promo code for an event
4
+ *
5
+ * Checks if a promo code is valid and returns its effects:
6
+ * - Discount amount and type
7
+ * - Hidden ticket reveal
8
+ *
9
+ * @param eventId - The event ID
10
+ * @param code - The promo code to validate
11
+ * @returns Validation result with discount info
12
+ */
13
+ export declare function validatePromoCode(eventId: string | number, code: string): Promise<PromoValidationResponse>;
14
+ /**
15
+ * Check if promo codes are available for an event
16
+ *
17
+ * Used to conditionally show/hide the promo code input field.
18
+ *
19
+ * @param eventId - The event ID
20
+ * @returns Whether promo codes exist for this event
21
+ */
22
+ export declare function hasPromoCodes(eventId: string | number): Promise<boolean>;
23
+ /**
24
+ * Apply a promo code to a cart
25
+ *
26
+ * This updates the cart with the promo code discount.
27
+ *
28
+ * @param cartId - The cart UUID
29
+ * @param code - The promo code to apply
30
+ * @returns Success status
31
+ */
32
+ export declare function applyPromoCode(cartId: string, code: string, productQuantities?: Record<string | number, number>): Promise<{
33
+ success: boolean;
34
+ error?: string;
35
+ }>;
36
+ /**
37
+ * Remove a promo code from a cart
38
+ *
39
+ * @param cartId - The cart UUID
40
+ * @returns Success status
41
+ */
42
+ export declare function removePromoCode(cartId: string): Promise<{
43
+ success: boolean;
44
+ error?: string;
45
+ }>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Result — the canonical error channel for API loaders.
3
+ *
4
+ * The public loaders in this package historically collapsed a failed fetch
5
+ * to an empty value (`[]`, `{ performers: [], showPerformers: false }`, or
6
+ * `null`), which is indistinguishable from a genuinely empty result. A buyer
7
+ * hitting a live event during a transient endpoint blip then sees a dead
8
+ * "No tickets available" button with no retry; a failed calendar month
9
+ * renders dark, so the venue looks like it has nothing on.
10
+ *
11
+ * `Result<T>` gives loaders a typed error channel so callers can tell
12
+ * "the request failed" apart from "there is genuinely nothing here", and
13
+ * offer a retry instead of silently degrading. Loaders expose a `*Result`
14
+ * variant returning this; the array/object-returning public functions stay
15
+ * as thin fail-open adapters over that variant (single source of truth for
16
+ * the fetch + validation logic).
17
+ *
18
+ * Not to be confused with `ApiResponse<T>` (types.ts) — that is the write-path
19
+ * HTTP envelope returned by `apiPost`/`apiGet`/etc. (`{ success, data?, error?,
20
+ * statusCode? }`, discriminated on `.success`). `Result<T>` is the read-path
21
+ * loader channel, discriminated on `.ok`. They are deliberately separate:
22
+ * `ApiResponse` carries transport metadata, `Result` carries only "loaded vs
23
+ * failed". Check `.ok` on a Result, `.success` on an ApiResponse — never mix.
24
+ */
25
+ export type Result<T> = {
26
+ ok: true;
27
+ data: T;
28
+ } | {
29
+ ok: false;
30
+ error: string;
31
+ notFound?: boolean;
32
+ };
33
+ /** Wrap a successful value. */
34
+ export declare function ok<T>(data: T): Result<T>;
35
+ /**
36
+ * Wrap a failure with a short, stable error code (used for i18n/render).
37
+ *
38
+ * This is a TRANSIENT failure by default (`notFound` is unset) — the request
39
+ * couldn't complete (network, timeout, 5xx). Loaders that gate an SSR 404 on a
40
+ * Result must treat a plain `err(...)` as retryable (503), not "gone" (404), so
41
+ * a backend blip never renders a permanent-looking 404 to a buyer or crawler.
42
+ */
43
+ export declare function err(error: string): Result<never>;
44
+ /**
45
+ * Wrap a genuine "this resource does not exist" failure (upstream 404).
46
+ *
47
+ * Distinct from `err(...)`: only this warrants an SSR 404. A transient upstream
48
+ * failure must NOT collapse to `errNotFound` — that is exactly the bug this
49
+ * channel exists to prevent (a fetch blip becoming a permanent 404).
50
+ */
51
+ export declare function errNotFound(error: string): Result<never>;
52
+ /** Narrowing guard — true when the result carries data. */
53
+ export declare function isOk<T>(result: Result<T>): result is {
54
+ ok: true;
55
+ data: T;
56
+ };
57
+ /**
58
+ * Narrowing guard — true when the result is a failure (transient OR not-found).
59
+ *
60
+ * This package typechecks with `strictNullChecks` off, where the ELSE flow of a
61
+ * discriminated union does NOT narrow (`if (r.ok) {…}` narrows the positive
62
+ * branch, but the fall-through keeps the full union). Consumers that need the
63
+ * failure branch's `error`/`notFound` must narrow POSITIVELY through this guard
64
+ * rather than relying on `!r.ok` control flow.
65
+ */
66
+ export declare function isErr<T>(result: Result<T>): result is {
67
+ ok: false;
68
+ error: string;
69
+ notFound?: boolean;
70
+ };
71
+ /**
72
+ * Collapse a Result to its data, substituting `fallback` on failure.
73
+ *
74
+ * This is the fail-open bridge the legacy array/object-returning loaders use
75
+ * so existing callers keep their current "degrade to empty" behaviour until
76
+ * they adopt the Result variant and render an error/retry state.
77
+ */
78
+ export declare function unwrapOr<T>(result: Result<T>, fallback: T): T;
@@ -0,0 +1,206 @@
1
+ /**
2
+ * The wire contract: every backend route this repo names.
3
+ *
4
+ * A test that asserts a route NAME proves nothing unless it proves the name
5
+ * RESOLVES. `expect(fetch).toHaveBeenCalledWith('/api/…')` passes happily
6
+ * against a route the router 404s — that is how 4.0.96 shipped a POST against a
7
+ * route the backend did not serve and locked every buyer out of every
8
+ * password-protected event.
9
+ *
10
+ * This module is the single source of truth two gates read:
11
+ *
12
+ * route-answers-contract.test.ts (every PR, offline)
13
+ * every API call site in src/ must name a route listed here, with a verb
14
+ * and body shape that match.
15
+ *
16
+ * route-answers-probe.test.ts (CI job, hits the deployed backend)
17
+ * every route listed here must be ANSWERED by the router. That is what
18
+ * keeps this file from being fiction.
19
+ *
20
+ * ROUTER-404 vs RESOURCE-404 — the whole diagnosis. The backend replies to an
21
+ * unrouted request with a 404 whose SHAPE depends on which host answered: the
22
+ * public host names it back (`{"code":"NOT_FOUND","message":"Route not found:
23
+ * POST /api/…"}`), the orders-v2 host answers a generic `{"code":"NOT_FOUND",
24
+ * "message":"Not Found"}` (#808). A route that EXISTS but whose resource does
25
+ * not replies 400 "Invalid event ID", or 404 "Order not found" / CART_NOT_FOUND,
26
+ * or 401, or 200 — a RESOURCE-level answer. `isRouterNotFound()` below is the one
27
+ * place that distinction is made, per-host.
28
+ *
29
+ * PROBE SAFETY. The probe test asks PRODUCTION. A probe recipe is only correct if
30
+ * it CANNOT MUTATE — and that claim is worthless unless something checks it. It
31
+ * is load-bearing, not decorative: `POST /orders/create` with an EMPTY body
32
+ * answers 200 and creates a real order.
33
+ *
34
+ * So every mutating row (POST/PUT/DELETE) must declare `probe.safety`, and
35
+ * route-answers-probe.test.ts asserts the declaration against what production
36
+ * actually answers. That holds for EVERY mutating row in BOTH lists — an UNSERVED
37
+ * row is not exempt. "It is a router-404, so no handler runs" is circular: it is
38
+ * true until the day the row's whole purpose is fulfilled and the backend ships the
39
+ * route. The probe sends the request BEFORE it can know whether the name resolved,
40
+ * so on that day the POST lands on a live handler, and the safety claim is the only
41
+ * thing asserting it bounced. Two shapes are legal, and only two:
42
+ *
43
+ * refused — the handler REJECTS the recipe (400 invalid id, 401, 404, 422) and
44
+ * never reaches its write. Assert the status is one it declared.
45
+ *
46
+ * inert — the handler ACCEPTS the recipe but it targets a resource that
47
+ * cannot exist, so it changes nothing, and the response SAYS SO.
48
+ * `POST /orders/complete/:uuid` is a bulk update keyed on the UUID:
49
+ * it answers 200 "Completed 0 reservations" for every UUID, refusing
50
+ * nothing — there is no rejecting recipe to write. Assert the row
51
+ * count in the body: the response itself proves zero rows moved.
52
+ *
53
+ * A row that cannot honestly claim either shape must not be probed at all.
54
+ */
55
+ /** Host prefixes. `client.ts` prefixes any endpoint not starting with `http`
56
+ * with PUBLIC — a bare `/orders/create` means `${PUBLIC}/orders/create`. */
57
+ export declare const PUBLIC = "/api/v2/public";
58
+ export declare const ORDERS_V2 = "/api/orders/v2/public";
59
+ export declare const ORDERS_V2_ROOT = "/api/orders/v2";
60
+ /**
61
+ * The verbs this contract knows — runtime, not just a type. The source scanner in
62
+ * route-answers-contract.test.ts checks a call site's `method:` against THIS list
63
+ * and goes red on anything else. When the scanner carried its own regex
64
+ * alternation instead, a `method: 'PATCH'` matched nothing, fell through to the
65
+ * `'GET'` default and was checked against the GET row: green, silently, at a route
66
+ * that serves no PATCH. One list, read by both.
67
+ */
68
+ export declare const HTTP_METHODS: readonly ["GET", "HEAD", "POST", "PUT", "DELETE"];
69
+ export type HttpMethod = (typeof HTTP_METHODS)[number];
70
+ /** Whether a verb written at a call site is one this contract can reason about. */
71
+ export declare function isHttpMethod(verb: string): verb is HttpMethod;
72
+ /**
73
+ * Why a probe cannot mutate production — see PROBE SAFETY above. Required on
74
+ * every POST/PUT/DELETE row and asserted live; the offline gate fails a mutating
75
+ * row that omits it, so the safety claim can never again be author discipline.
76
+ */
77
+ export type ProbeSafety = {
78
+ kind: 'refused';
79
+ /** Statuses the handler answers when it refuses this recipe. Never 2xx. */
80
+ statuses: readonly number[];
81
+ } | {
82
+ kind: 'inert';
83
+ /** The status the handler answers when it accepts this recipe. */
84
+ status: number;
85
+ /** Must match the response body, and must prove nothing was written. */
86
+ proof: RegExp;
87
+ /** Why accepting it changes nothing. */
88
+ why: string;
89
+ };
90
+ export interface Probe {
91
+ path: string;
92
+ body?: unknown;
93
+ headers?: Record<string, string>;
94
+ /** Required on POST/PUT/DELETE. Reads cannot mutate, so GET/HEAD omit it. */
95
+ safety?: ProbeSafety;
96
+ }
97
+ export interface BackendRoute {
98
+ method: HttpMethod;
99
+ /** Full path from the host root. Path params are written `:name`. */
100
+ path: string;
101
+ /** Whether the route takes a request body. */
102
+ body: 'required' | 'none';
103
+ /** A request that reaches the router and cannot change anything behind it. */
104
+ probe: Probe;
105
+ }
106
+ /** The verbs that can write. These are the probes that need a safety claim. */
107
+ export declare function isMutating(method: HttpMethod): boolean;
108
+ /** Turn a manifest pattern into a matcher: `:name` matches any single segment. */
109
+ export declare function patternMatches(pattern: string, concrete: string): boolean;
110
+ /**
111
+ * A path param value that is syntactically valid and cannot exist.
112
+ *
113
+ * Exported because production code needs it too: `testNetworkConnection()` asks a
114
+ * SERVED route about this id to find out whether the router answers at all. Same
115
+ * id, same reason, one definition — an id-that-cannot-exist written out twice is
116
+ * two ids that can drift.
117
+ */
118
+ export declare const NONEXISTENT_ID = "00000000-0000-0000-0000-000000000000";
119
+ /**
120
+ * Routes the deployed backend ANSWERS. Verified by route-answers-probe.test.ts.
121
+ * Adding a row here without the probe agreeing is exactly the lie this gate exists
122
+ * to catch — the probe will fail the row.
123
+ */
124
+ export declare const SERVED_ROUTES: BackendRoute[];
125
+ export interface UnservedRoute extends Omit<BackendRoute, 'body'> {
126
+ /** Where the dead name is spoken. */
127
+ callSites: string[];
128
+ /** What the buyer sees because the name resolves to nothing. */
129
+ impact: string;
130
+ issue: string;
131
+ }
132
+ /**
133
+ * Routes this repo NAMES that the router does not serve — verified router-404.
134
+ *
135
+ * This is a debt ledger, not a sanctioned end-state. It exists so the gate can
136
+ * land red-free while every dead name stays visible and non-regressible: the
137
+ * contract test fails if a NEW call site names a route in neither list, and the
138
+ * probe fails if a route listed here starts answering (fix the call site, then
139
+ * move the row into SERVED_ROUTES). The list may only ever shrink.
140
+ */
141
+ export declare const UNSERVED_ROUTES: UnservedRoute[];
142
+ export interface RetiredRoute {
143
+ method: HttpMethod;
144
+ /** The dead name, exactly as the ledger row used to spell it. */
145
+ path: string;
146
+ /** Who used to speak it, and what happened to them. */
147
+ wasNamedBy: string;
148
+ issue: string;
149
+ }
150
+ /**
151
+ * Dead names this repo has STOPPED speaking. The ledger's graveyard.
152
+ *
153
+ * UNSERVED_ROUTES says "may only ever shrink" — and until now nothing enforced
154
+ * that. Two ways to put a dead name back were wide open: re-add the row, or write
155
+ * a fresh call site and baseline it. Either one turns the debt ledger into a
156
+ * silencer, and a silencer is how the 4.0.96 password outage shipped in the first
157
+ * place.
158
+ *
159
+ * So a retired route is retired in both directions, asserted in
160
+ * route-answers-contract.test.ts:
161
+ *
162
+ * - nothing in src/ may NAME it again (a new call site goes red, not baselined);
163
+ * - it may not reappear in UNSERVED_ROUTES (you cannot re-open the debt);
164
+ * - it may not appear in SERVED_ROUTES either — if the backend genuinely ships
165
+ * the route one day, DELETE the row here in the same commit that adds the
166
+ * served one with a probe recipe proving the router answers it. That is a
167
+ * deliberate two-place edit, which is the whole point: coming back from the
168
+ * dead should cost more than adding a line.
169
+ */
170
+ export declare const RETIRED_ROUTES: RetiredRoute[];
171
+ /**
172
+ * The router-404 discriminator — the one place the distinction is made.
173
+ *
174
+ * TRUE = the name resolved to nothing (the bug), per the answering HOST's
175
+ * unrouted-name shape.
176
+ * FALSE = the router answered; whatever the handler then said (400 invalid id,
177
+ * 404 "Order not found", 401, 501, 200) is a RESOURCE-level answer and
178
+ * is none of this gate's business — OR the path belongs to a host this
179
+ * manifest does not know, in which case no router-404 can be claimed and
180
+ * `hostsToCanary` is what fails closed on it.
181
+ *
182
+ * Takes the PATH, not just the body: the orders-v2 and public hosts answer a
183
+ * dead name with different bodies, so the body alone cannot be read without
184
+ * knowing which host produced it (#808).
185
+ */
186
+ export declare function isRouterNotFound(status: number, bodyText: string, path: string): boolean;
187
+ export interface CanaryHost {
188
+ /** Host label, for the canary's failure message. */
189
+ label: string;
190
+ /** A path under this host that no route serves — to probe its 404 shape. */
191
+ deadPath: (_nonce: string) => string;
192
+ }
193
+ /**
194
+ * The distinct hosts a set of probe paths touches, each with a dead-route path
195
+ * builder — so the canary can prove the discriminator works on EVERY host the
196
+ * manifest probes, derived from the rows rather than hardcoded, so a host added
197
+ * later cannot get a free pass (#808).
198
+ *
199
+ * FAILS CLOSED: a probe path that belongs to no known host throws here, because
200
+ * the discriminator cannot tell a dead name from a live one on a host whose 404
201
+ * shape it has never been taught. A new host prefix must be added to HOSTS (with
202
+ * its router-404 discriminator) before its rows can be trusted.
203
+ */
204
+ export declare function hostsToCanary(paths: readonly string[]): CanaryHost[];
205
+ /** HEAD is answered by the GET route — Express routes the two together. */
206
+ export declare function effectiveMethod(method: HttpMethod): HttpMethod;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Address helpers — shared between the event, series and collection page
3
+ * transformers.
4
+ *
5
+ * Lifted verbatim from public-calendar-flow/transform.ts so the series and
6
+ * collection canonicals (and the in-place transformApiEvent) read a single
7
+ * source instead of each carrying a private copy. Behavior is byte-identical
8
+ * to the previous module-private versions.
9
+ */
10
+ /**
11
+ * Parse a single-line address string into display lines.
12
+ * E.g. "123 Main St, Los Angeles, CA 90012" -> ["123 Main St", "Los Angeles, CA 90012"]
13
+ */
14
+ export declare function parseAddress(addressStr: string): string[];
15
+ /**
16
+ * Build a Google Maps search URL from an address string.
17
+ */
18
+ export declare function buildGoogleMapsUrl(address: string): string;
@@ -0,0 +1,34 @@
1
+ import { CartView, CartReservationView, CartGiftCardView } from '../orders.js';
2
+ /**
3
+ * Parse a single raw reservation row into the normalized CartReservationView.
4
+ *
5
+ * Wire shape is contained here. Uses `??` (PascalCase first, camelCase
6
+ * fallback) so a real `0` quantity / price is preserved. Numeric coercion via
7
+ * Number(), status via String() -- byte-identical to the inline `.map` in
8
+ * getCartByUUID.
9
+ */
10
+ export declare function parseCartReservation(raw: unknown): CartReservationView;
11
+ /**
12
+ * Parse one applied gift card.
13
+ *
14
+ * `maskedCode` is all the server will say — the code itself is a bearer
15
+ * instrument and this cart endpoint is public, keyed only by the cart UUID — so
16
+ * removal is keyed by `giftCardId`. `amount` arrives in CENTS (the orders-service
17
+ * column) and is converted to DOLLARS here, because every gift-card figure the
18
+ * checkout UI handles downstream is in dollars.
19
+ *
20
+ * A missing or malformed amount parses to `null`, never 0. This value is what
21
+ * the panel says a card COVERS; a fabricated $0 would understate coverage and
22
+ * feed a wrong order ceiling back into the checkout. The consumer drops such an
23
+ * entry instead of drawing it (mf#2383).
24
+ */
25
+ export declare function parseCartGiftCard(raw: unknown): CartGiftCardView;
26
+ /**
27
+ * Parse a raw cart payload into the normalized CartView domain shape.
28
+ *
29
+ * Wire shape (RawCart) is contained inside this module and never escapes it.
30
+ * Reconciles PascalCase and camelCase JSON tags via `??`. Reservations are
31
+ * normalized through parseCartReservation. Byte-identical to the inline
32
+ * normalization previously embedded in getCartByUUID.
33
+ */
34
+ export declare function parseCart(raw: unknown): CartView;
@@ -0,0 +1,12 @@
1
+ import { PublicCollectionData } from '../types.js';
2
+ import { EventData } from '../../public-calendar-flow/types';
3
+ /**
4
+ * Transform PublicCollectionData (from the collection API) into our clean EventData interface.
5
+ * Sets collectionId so EventExperience renders in full-width collection mode.
6
+ */
7
+ export declare function parseCollection(collection: PublicCollectionData): EventData;
8
+ /**
9
+ * Back-compat alias — the public-calendar-flow shaper name. Existing call
10
+ * sites importing transformCollectionData continue to work unchanged.
11
+ */
12
+ export declare const transformCollectionData: typeof parseCollection;