{"version":3,"file":"api.mjs","sources":["../../src/lib/api/client.ts","../../src/lib/api/transformers/cart.ts","../../src/lib/tracking/normalize.ts","../../src/lib/tracking/context.ts","../../src/lib/tracking/consent.ts","../../src/lib/tracking/identity.ts","../../src/lib/tracking/attribution-store.ts","../../src/lib/tracking/beacon.ts","../../src/lib/api/orders.ts","../../src/lib/api/promo.ts","../../src/lib/api/transformers/performer.ts","../../src/lib/api/result.ts","../../src/lib/api/events.ts","../../src/lib/api/venues.ts","../../src/lib/api/transformers/giftCard.ts","../../src/lib/api/gift-cards.ts","../../src/lib/api/waitlist.ts","../../src/lib/api/cta.ts","../../src/lib/api/transformers/order.ts","../../src/lib/api/transformers/event.ts","../../src/lib/api/transformers/venue.ts"],"sourcesContent":["/**\r\n * API Client for MicDrop Public Checkout API\r\n *\r\n * Provides a centralized HTTP client with:\r\n * - Configurable base URL\r\n * - Per-request timeout via AbortController\r\n * - Exponential-backoff retry on 5xx and network errors (idempotent methods)\r\n * - Consistent error surfacing\r\n * - Request/response typing\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nconst logger = createLogger('VC');\r\nimport type { ApiConfig, ApiResponse } from './types.js';\r\n\r\n// Default API configuration\r\nconst DEFAULT_CONFIG: Required<ApiConfig> = {\r\n  baseUrl: 'https://get-micdrop.com',\r\n  timeout: 30000,\r\n  retries: 2,\r\n  retryDelay: 500,\r\n  onError: (error: Error) => logger.error('API Error:', error),\r\n};\r\n\r\nlet globalConfig: Required<ApiConfig> = { ...DEFAULT_CONFIG };\r\n\r\nexport function configureApi(config: Partial<ApiConfig>): void {\r\n  globalConfig = { ...globalConfig, ...config };\r\n}\r\n\r\nexport function getApiConfig(): Required<ApiConfig> {\r\n  return { ...globalConfig };\r\n}\r\n\r\nexport function getPublicBaseUrl(): string {\r\n  return `${globalConfig.baseUrl}/api/v2/public`;\r\n}\r\n\r\nexport function getLegacyPublicUrl(): string {\r\n  return `${globalConfig.baseUrl}/api/public`;\r\n}\r\n\r\nexport function getOrdersV2Url(): string {\r\n  return `${globalConfig.baseUrl}/api/orders/v2/public`;\r\n}\r\n\r\n/** @deprecated IP is now resolved server-side via request headers. */\r\nexport async function getClientIP(): Promise<string> {\r\n  return '';\r\n}\r\n\r\n/**\r\n * Sleep utility for retry backoff.\r\n */\r\nconst sleep = (ms: number): Promise<void> =>\r\n  new Promise(resolve => setTimeout(resolve, ms));\r\n\r\n/**\r\n * fetch with timeout, idempotent retry, and exponential backoff.\r\n *\r\n * - Retries on network errors and 5xx (transient) responses.\r\n * - Auto-retries GET/HEAD only. This is DELIBERATELY narrower than SC's\r\n *   canonical `IDEMPOTENT` set (GET/PUT/DELETE/HEAD/OPTIONS): although PUT and\r\n *   DELETE are HTTP-spec idempotent, \"spec-idempotent\" is not the same as\r\n *   \"safe to blind-retry a write on a public checkout flow\". A transient 5xx\r\n *   can arrive *after* the server already applied the write (e.g. a 504 on a\r\n *   lost response), so auto-retrying a PUT/DELETE risks a double-apply on the\r\n *   buyer-facing cart/order endpoints. VC leaves write-retries to caller-driven\r\n *   logic instead. See the blade b5-request-lifecycle-residual packet.\r\n * - The supplied AbortSignal (if any) is respected and short-circuits retries.\r\n */\r\nasync function fetchWithRetry(\r\n  url: string,\r\n  init: RequestInit,\r\n  cfg: Required<ApiConfig>\r\n): Promise<Response> {\r\n  const method = (init.method || 'GET').toUpperCase();\r\n  // @api-client-escape: retry set is intentionally GET/HEAD only, narrower than\r\n  // SC's IDEMPOTENT canon — see the fetchWithRetry docstring for why (checkout\r\n  // write-safety), a documented divergence, not undeclared drift.\r\n  const isIdempotent = method === 'GET' || method === 'HEAD';\r\n  const maxAttempts = isIdempotent ? cfg.retries + 1 : 1;\r\n\r\n  let lastError: unknown;\r\n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\r\n    const controller = new AbortController();\r\n    const timeoutId = setTimeout(() => controller.abort(), cfg.timeout);\r\n\r\n    // Chain the caller's signal if provided.\r\n    const callerSignal = init.signal;\r\n    let onCallerAbort: (() => void) | undefined;\r\n    if (callerSignal) {\r\n      if (callerSignal.aborted) controller.abort();\r\n      else {\r\n        onCallerAbort = () => controller.abort();\r\n        callerSignal.addEventListener('abort', onCallerAbort, { once: true });\r\n      }\r\n    }\r\n\r\n    try {\r\n      // @api-client-escape: internal canonical client implementation — not drift\r\n      const response = await fetch(url, { ...init, signal: controller.signal });\r\n\r\n      // Retry transient server errors.\r\n      if (response.status >= 500 && attempt < maxAttempts) {\r\n        lastError = new Error(`HTTP ${response.status}`);\r\n      } else {\r\n        return response;\r\n      }\r\n    } catch (err) {\r\n      lastError = err;\r\n      // Caller aborted — give up.\r\n      if (callerSignal?.aborted) throw err;\r\n    } finally {\r\n      clearTimeout(timeoutId);\r\n      if (callerSignal && onCallerAbort) {\r\n        callerSignal.removeEventListener('abort', onCallerAbort);\r\n      }\r\n    }\r\n\r\n    if (attempt < maxAttempts) {\r\n      await sleep(cfg.retryDelay * Math.pow(2, attempt - 1));\r\n    }\r\n  }\r\n\r\n  throw lastError;\r\n}\r\n\r\nexport async function apiGet<T>(\r\n  endpoint: string,\r\n  options?: RequestInit\r\n): Promise<ApiResponse<T>> {\r\n  return apiRequest<T>('GET', endpoint, undefined, options);\r\n}\r\n\r\nexport async function apiPost<T>(\r\n  endpoint: string,\r\n  body?: unknown,\r\n  options?: RequestInit\r\n): Promise<ApiResponse<T>> {\r\n  return apiRequest<T>('POST', endpoint, body, options);\r\n}\r\n\r\nexport async function apiPut<T>(\r\n  endpoint: string,\r\n  body?: unknown,\r\n  options?: RequestInit\r\n): Promise<ApiResponse<T>> {\r\n  return apiRequest<T>('PUT', endpoint, body, options);\r\n}\r\n\r\nexport async function apiDelete<T>(\r\n  endpoint: string,\r\n  options?: RequestInit\r\n): Promise<ApiResponse<T>> {\r\n  return apiRequest<T>('DELETE', endpoint, undefined, options);\r\n}\r\n\r\nasync function apiRequest<T>(\r\n  method: string,\r\n  endpoint: string,\r\n  body?: unknown,\r\n  options?: RequestInit\r\n): Promise<ApiResponse<T>> {\r\n  const url = endpoint.startsWith('http')\r\n    ? endpoint\r\n    : `${getPublicBaseUrl()}${endpoint}`;\r\n\r\n  try {\r\n    const response = await fetchWithRetry(\r\n      url,\r\n      {\r\n        method,\r\n        headers: {\r\n          'Content-Type': 'application/json',\r\n          ...options?.headers,\r\n        },\r\n        body: body !== undefined ? JSON.stringify(body) : undefined,\r\n        credentials: 'include',\r\n        ...options,\r\n      },\r\n      globalConfig\r\n    );\r\n\r\n    if (!response.ok) {\r\n      const errorData = await response.json().catch(() => ({}));\r\n      const message =\r\n        errorData.error || errorData.message || `HTTP ${response.status}`;\r\n      globalConfig.onError(new Error(message));\r\n      return { success: false, error: message, statusCode: response.status };\r\n    }\r\n\r\n    const data = await response.json();\r\n    return { success: true, data: data as T, statusCode: response.status };\r\n  } catch (error) {\r\n    const errorMessage =\r\n      error instanceof Error\r\n        ? error.name === 'AbortError'\r\n          ? 'Request timed out'\r\n          : error.message\r\n        : 'Unknown error';\r\n\r\n    globalConfig.onError(\r\n      error instanceof Error ? error : new Error(errorMessage)\r\n    );\r\n    return { success: false, error: errorMessage };\r\n  }\r\n}\r\n\r\n/**\r\n * Simple fetch wrapper that returns parsed JSON or null on error.\r\n * Inherits the global timeout + retry policy for GETs.\r\n */\r\nexport async function simpleFetch<T>(\r\n  url: string,\r\n  options?: RequestInit\r\n): Promise<T | null> {\r\n  try {\r\n    const response = await fetchWithRetry(\r\n      url,\r\n      { credentials: 'include', ...options },\r\n      globalConfig\r\n    );\r\n\r\n    if (!response.ok) {\r\n      const errorData = await response.json().catch(() => ({}));\r\n      logger.error(`API request failed: ${response.status}`, errorData);\r\n      return null;\r\n    }\r\n\r\n    return response.json();\r\n  } catch (error) {\r\n    logger.error('API request error:', error);\r\n    return null;\r\n  }\r\n}\r\n","/**\r\n * Cart Transformer\r\n *\r\n * Normalizes the orders-service `GET /v2Public/cart/{uuid}` response into the\r\n * domain CartView / CartReservationView shapes.\r\n *\r\n * Wire->domain boundary: one parseCart(raw: unknown) entry point plus a\r\n * parseCartReservation(raw: unknown) sub-parse. The wire field shapes\r\n * (RawCart / RawReservation) are named ONLY inside this module and never escape.\r\n *\r\n * IMPLEMENTATION NOTE -- PascalCase reconciliation:\r\n * The orders-service Cart model uses Go-style PascalCase JSON tags\r\n * (UUID, EventID, Status, ExpiresAt, Reservations) on some routes and\r\n * camelCase on the newer v2 routes. We tolerate both via `??` (NOT `||`):\r\n * `??` only falls through on null/undefined, so a legitimate `0` eventID or\r\n * empty-string status is preserved -- byte-identical to the inline mapper this\r\n * was lifted from (src/lib/api/orders.ts getCartByUUID). Numeric fields are\r\n * coerced with Number(), string fields with String(), exactly as before.\r\n *\r\n * Staleness/event-mismatch policy (status must be reserved|active, eventID must\r\n * match the expected event) is a CALLER decision and intentionally stays in\r\n * getCartByUUID -- it is not part of normalization.\r\n */\r\n\r\nimport type { CartView, CartReservationView } from '../orders.js';\r\n\r\n// -- Wire shapes (internal -- never exported) --------------------------------\r\ninterface RawCart {\r\n  UUID?: string;\r\n  uuid?: string;\r\n  EventID?: number;\r\n  eventID?: number;\r\n  Status?: string;\r\n  status?: string;\r\n  ExpiresAt?: string;\r\n  expiresAt?: string;\r\n  Reservations?: unknown[];\r\n  reservations?: unknown[];\r\n}\r\n\r\n/**\r\n * Parse a single raw reservation row into the normalized CartReservationView.\r\n *\r\n * Wire shape is contained here. Uses `??` (PascalCase first, camelCase\r\n * fallback) so a real `0` quantity / price is preserved. Numeric coercion via\r\n * Number(), status via String() -- byte-identical to the inline `.map` in\r\n * getCartByUUID.\r\n */\r\nexport function parseCartReservation(raw: unknown): CartReservationView {\r\n  const rec = (raw ?? {}) as Record<string, unknown>;\r\n  return {\r\n    ticketID: Number(rec.TicketID ?? rec.ticketID ?? 0),\r\n    quantity: Number(rec.Quantity ?? rec.quantity ?? 0),\r\n    priceAtReservation: Number(\r\n      rec.PriceAtReservation ?? rec.priceAtReservation ?? 0\r\n    ),\r\n    status: String(rec.Status ?? rec.status ?? ''),\r\n  };\r\n}\r\n\r\n/**\r\n * Parse a raw cart payload into the normalized CartView domain shape.\r\n *\r\n * Wire shape (RawCart) is contained inside this module and never escapes it.\r\n * Reconciles PascalCase and camelCase JSON tags via `??`. Reservations are\r\n * normalized through parseCartReservation. Byte-identical to the inline\r\n * normalization previously embedded in getCartByUUID.\r\n */\r\nexport function parseCart(raw: unknown): CartView {\r\n  const data = (raw ?? {}) as RawCart;\r\n  const uuid: string = data.UUID ?? data.uuid ?? '';\r\n  const eventID = Number(data.EventID ?? data.eventID ?? 0);\r\n  const status: string = data.Status ?? data.status ?? '';\r\n  const expiresAt: string = data.ExpiresAt ?? data.expiresAt ?? '';\r\n  const rawRes: unknown[] = data.Reservations ?? data.reservations ?? [];\r\n  const reservations: CartReservationView[] = rawRes.map(parseCartReservation);\r\n  return { uuid, eventID, status, expiresAt, reservations };\r\n}\r\n","/**\r\n * UTM normalization — the single write-time normalizer shared by every beacon\r\n * moment and the attribution store.\r\n *\r\n * Kills the historical fragmentation (`Facebook` vs `facebook`, `Direct` vs\r\n * `''` vs `direct`): every utm value is lowercased, trimmed, and has internal\r\n * whitespace collapsed to underscores at WRITE time, and an empty source\r\n * resolves to the ONE canonical default `direct`. Downstream marketing reports\r\n * then bucket page-views and order rows into the same key.\r\n *\r\n * No svelte-components canonical covers this (checked the MCP: `slugify` uses\r\n * hyphen/URL semantics and no `direct` default; `normalize*` transforms are\r\n * status/timezone/charge specific). This is the widget-local tracking\r\n * canonical for the utm write contract (MISSION-TRUTH C1).\r\n */\r\n\r\n/** The five utm dimensions, in canonical order. */\r\nexport const UTM_KEYS = [\r\n  'utmSource',\r\n  'utmMedium',\r\n  'utmCampaign',\r\n  'utmContent',\r\n  'utmTerm',\r\n] as const;\r\n\r\nexport type UtmKey = (typeof UTM_KEYS)[number];\r\n\r\n/** Query-param name for each utm dimension. */\r\nconst UTM_PARAM: Record<UtmKey, string> = {\r\n  utmSource: 'utm_source',\r\n  utmMedium: 'utm_medium',\r\n  utmCampaign: 'utm_campaign',\r\n  utmContent: 'utm_content',\r\n  utmTerm: 'utm_term',\r\n};\r\n\r\nexport type UtmSet = Record<UtmKey, string>;\r\n\r\n/** The one default source — used everywhere an empty source would otherwise appear. */\r\nexport const DIRECT_SOURCE = 'direct';\r\n\r\n/**\r\n * Normalize a single utm value: trim, lowercase, collapse internal whitespace\r\n * to underscores. Empty stays empty here (source-specific defaulting to\r\n * `direct` happens in {@link normalizeUtmSet} so medium/campaign/etc. can stay\r\n * genuinely empty).\r\n */\r\nexport function normalizeUtmValue(raw: string | null | undefined): string {\r\n  if (!raw) return '';\r\n  return raw.trim().toLowerCase().replace(/\\s+/g, '_');\r\n}\r\n\r\n/**\r\n * Normalize a full utm set. Every value is run through\r\n * {@link normalizeUtmValue}; an empty `utmSource` resolves to `direct` (the\r\n * single canonical default). The other four dimensions stay empty when absent.\r\n */\r\nexport function normalizeUtmSet(\r\n  raw: Partial<Record<UtmKey, string | null | undefined>>\r\n): UtmSet {\r\n  const out = {} as UtmSet;\r\n  for (const key of UTM_KEYS) {\r\n    out[key] = normalizeUtmValue(raw[key]);\r\n  }\r\n  if (!out.utmSource) out.utmSource = DIRECT_SOURCE;\r\n  return out;\r\n}\r\n\r\n/**\r\n * Read + normalize the utm set from URL search params (or any\r\n * `URLSearchParams`). Used at every host-context read so a beacon fired from a\r\n * `?utm_source=Instagram` visit records `instagram`.\r\n */\r\nexport function readUtmSet(params: URLSearchParams): UtmSet {\r\n  const raw = {} as Record<UtmKey, string | null>;\r\n  for (const key of UTM_KEYS) {\r\n    raw[key] = params.get(UTM_PARAM[key]);\r\n  }\r\n  return normalizeUtmSet(raw);\r\n}\r\n\r\n/**\r\n * True when a normalized utm set represents a real marketing touch (an\r\n * explicit non-direct source). Drives the attribution store's\r\n * last-non-direct-touch overwrite rule.\r\n */\r\nexport function isMarketingUtm(utm: UtmSet): boolean {\r\n  return !!utm.utmSource && utm.utmSource !== DIRECT_SOURCE;\r\n}\r\n","/**\r\n * Tracking host-context (MISSION-TRUTH C1).\r\n *\r\n * Every beacon and the attribution store read the visitor's marketing context\r\n * — utm params + referrer + page url — from HERE, never from `window.location`\r\n * at call time. Two reasons:\r\n *   1. The standalone checkout route drops query params, so a live read at\r\n *      purchase time would see nothing (that's why attribution is stored, C2).\r\n *   2. Iframe embed mode: the frame's own `window.location` is Micdrop's, not\r\n *      the host page's. `setForwardedHostContext` lets the embed layer push the\r\n *      host page's real utm + referrer into the frame (via its iframe src query\r\n *      string or a host→widget postMessage), and this module prefers it.\r\n *\r\n * `widgetId` / `venueId` are set once at widget init and threaded onto every\r\n * beacon so per-widget traffic is attributable (decision 14).\r\n *\r\n * No svelte-components canonical covers host-context resolution (checked the\r\n * MCP); this is widget-local tracking plumbing.\r\n */\r\nimport { readUtmSet, type UtmSet } from './normalize.js';\r\n\r\nexport type DeviceType = 'mobile' | 'desktop' | 'tablet';\r\n\r\nexport interface HostContext {\r\n  utm: UtmSet;\r\n  referrer: string;\r\n  pageUrl: string;\r\n}\r\n\r\ninterface ForwardedContext {\r\n  search: string | null;\r\n  referrer: string | null;\r\n  pageUrl: string | null;\r\n}\r\n\r\nlet widgetId: string | null = null;\r\nlet venueId: string | number | null = null;\r\nconst forwarded: ForwardedContext = {\r\n  search: null,\r\n  referrer: null,\r\n  pageUrl: null,\r\n};\r\n\r\n/** Set once at widget init from the embed attributes / init options. */\r\nexport function setTrackingContext(ctx: {\r\n  widgetId?: string | null;\r\n  venueId?: string | number | null;\r\n}): void {\r\n  if (ctx.widgetId !== undefined) widgetId = ctx.widgetId || null;\r\n  if (ctx.venueId !== undefined) venueId = ctx.venueId ?? null;\r\n}\r\n\r\n/**\r\n * Push the host page's real marketing context into the frame (iframe embed\r\n * mode). Accepts a raw query string / URLSearchParams for utm and the host\r\n * page's referrer + url. Any field left undefined keeps the current value, so a\r\n * partial forward (utm now, referrer later) composes.\r\n */\r\nexport function setForwardedHostContext(ctx: {\r\n  search?: string | URLSearchParams | null;\r\n  referrer?: string | null;\r\n  pageUrl?: string | null;\r\n}): void {\r\n  if (ctx.search !== undefined) {\r\n    forwarded.search =\r\n      ctx.search === null\r\n        ? null\r\n        : ctx.search instanceof URLSearchParams\r\n          ? ctx.search.toString()\r\n          : ctx.search;\r\n  }\r\n  if (ctx.referrer !== undefined) forwarded.referrer = ctx.referrer;\r\n  if (ctx.pageUrl !== undefined) forwarded.pageUrl = ctx.pageUrl;\r\n}\r\n\r\nexport function getWidgetId(): string | null {\r\n  return widgetId;\r\n}\r\n\r\nexport function getVenueId(): string | number | null {\r\n  return venueId;\r\n}\r\n\r\n/**\r\n * True when this document is the top-level window (light-DOM script embed).\r\n * False inside an iframe, where `window.location` is Micdrop's frame — NOT the\r\n * host page — so it must not be trusted as the host context. Cross-origin\r\n * access to `window.top` can throw; that itself means we're framed.\r\n */\r\nfunction isTopLevel(): boolean {\r\n  if (typeof window === 'undefined') return true;\r\n  try {\r\n    return window.self === window.top;\r\n  } catch {\r\n    return false;\r\n  }\r\n}\r\n\r\n/**\r\n * Resolve the current host context. Prefers forwarded values (iframe mode);\r\n * otherwise reads the live document — which is the host page itself in the\r\n * light-DOM script embed. `pageUrl` falls back to the live URL ONLY at the top\r\n * level: inside an unforwarded iframe the frame's own URL is Micdrop's, not the\r\n * host page's, so it's left empty rather than misrepresenting the host (which\r\n * would also mis-classify the referrer, see attribution-store).\r\n */\r\nexport function resolveHostContext(): HostContext {\r\n  const hasWindow = typeof window !== 'undefined';\r\n  const topLevel = isTopLevel();\r\n  const search = forwarded.search ?? (hasWindow ? window.location.search : '');\r\n  const referrer =\r\n    forwarded.referrer ??\r\n    (typeof document !== 'undefined' ? document.referrer : '') ??\r\n    '';\r\n  const pageUrl =\r\n    forwarded.pageUrl ?? (hasWindow && topLevel ? window.location.href : '');\r\n\r\n  return {\r\n    utm: readUtmSet(new URLSearchParams(search)),\r\n    referrer: referrer || '',\r\n    pageUrl: pageUrl || '',\r\n  };\r\n}\r\n\r\n/** Coarse device class from the user-agent — a marketing dimension on every beacon. */\r\nexport function getDeviceType(): DeviceType {\r\n  if (typeof navigator === 'undefined') return 'desktop';\r\n  const ua = navigator.userAgent.toLowerCase();\r\n  if (/ipad|tablet|playbook|silk/.test(ua)) return 'tablet';\r\n  if (/mobile|iphone|ipod|android.*mobile|windows phone|blackberry/.test(ua))\r\n    return 'mobile';\r\n  if (/android/.test(ua)) return 'tablet';\r\n  return 'desktop';\r\n}\r\n\r\n/** Test-only reset of the module singleton. */\r\nexport function _resetContextForTests(): void {\r\n  widgetId = null;\r\n  venueId = null;\r\n  forwarded.search = null;\r\n  forwarded.referrer = null;\r\n  forwarded.pageUrl = null;\r\n}\r\n","/**\r\n * Consent gating (MISSION-TRUTH C5).\r\n *\r\n * When a host consent signal exists — the IAB TCF API (`window.__tcfapi`) or an\r\n * explicit embed flag — the persistent `visitorId` (and, later, pixels) wait\r\n * for consent to be granted. Until then beacons still fire, but fall back to\r\n * `sessionId`-only (no cross-visit identity). When NO consent signal exists at\r\n * all, the widget is free to use the visitorId immediately (the default embed\r\n * has no consent layer).\r\n *\r\n * This module holds the resolved consent state. It is deliberately synchronous\r\n * for the fire-and-forget beacon path: TCF is best-effort — presence flips\r\n * \"required\", and an async TCF listener flips \"granted\" when the user acts.\r\n */\r\n\r\ninterface TcfData {\r\n  gdprApplies?: boolean;\r\n  eventStatus?: string;\r\n  // `1` = vendor/purpose consent present for the queried scope.\r\n  purpose?: { consents?: Record<string, boolean> };\r\n}\r\ntype TcfApi = (\r\n  _command: string,\r\n  _version: number,\r\n  _callback: (_data: TcfData, _success: boolean) => void,\r\n  ..._args: unknown[]\r\n) => void;\r\n\r\nlet explicitRequire: boolean | null = null;\r\nlet granted = false;\r\nlet tcfWired = false;\r\n\r\n/** Host explicitly declares whether embed-level consent is required. */\r\nexport function setConsentRequired(required: boolean): void {\r\n  explicitRequire = required;\r\n}\r\n\r\n/** Host (or its consent listener) declares consent granted/withdrawn. */\r\nexport function setConsentGranted(value: boolean): void {\r\n  granted = value;\r\n}\r\n\r\nfunction hasTcf(): boolean {\r\n  return (\r\n    typeof window !== 'undefined' &&\r\n    typeof (window as unknown as { __tcfapi?: TcfApi }).__tcfapi === 'function'\r\n  );\r\n}\r\n\r\n/**\r\n * A consent signal exists when the host set the explicit flag OR the TCF API is\r\n * present on the page. Explicit flag wins (a host may run TCF but opt the\r\n * widget out, or force consent without TCF).\r\n */\r\nexport function isConsentRequired(): boolean {\r\n  if (explicitRequire !== null) return explicitRequire;\r\n  return hasTcf();\r\n}\r\n\r\n/**\r\n * True when the persistent visitorId may be used: either no consent signal\r\n * exists, or one exists and consent has been granted.\r\n */\r\nexport function isConsentGranted(): boolean {\r\n  if (!isConsentRequired()) return true;\r\n  return granted;\r\n}\r\n\r\n/**\r\n * Best-effort TCF wiring. Registers a listener that flips `granted` once the CMP\r\n * reports a loaded/complete state with GDPR consent. Safe to call repeatedly\r\n * (wires once). No-op when TCF is absent.\r\n */\r\nexport function wireTcfConsent(): void {\r\n  if (tcfWired || !hasTcf()) return;\r\n  tcfWired = true;\r\n  const tcf = (window as unknown as { __tcfapi: TcfApi }).__tcfapi;\r\n  try {\r\n    tcf('addEventListener', 2, (data, success) => {\r\n      if (!success || !data) return;\r\n      // If GDPR doesn't apply the CMP is effectively pass-through → treat as\r\n      // granted. Otherwise wait for a settled CMP state (tcloaded /\r\n      // useractioncomplete) before honoring consent.\r\n      if (data.gdprApplies === false) {\r\n        granted = true;\r\n        return;\r\n      }\r\n      if (\r\n        data.eventStatus === 'tcloaded' ||\r\n        data.eventStatus === 'useractioncomplete'\r\n      ) {\r\n        // Presence of any purpose consent is enough for first-party analytics\r\n        // identity; the backend treats visitorId as opaque.\r\n        const consents = data.purpose?.consents;\r\n        granted = !!consents && Object.values(consents).some(Boolean);\r\n      }\r\n    });\r\n  } catch {\r\n    // A malformed CMP shim must never break tracking — stay ungranted.\r\n  }\r\n}\r\n\r\n/** Test-only reset of the module singleton. */\r\nexport function _resetConsentForTests(): void {\r\n  explicitRequire = null;\r\n  granted = false;\r\n  tcfWired = false;\r\n}\r\n","/**\r\n * Visitor + session identity (MISSION-TRUTH C1 + C5).\r\n *\r\n * - `sessionId`: per-tab, sessionStorage, created once and reused — the same\r\n *   `micdrop_session_id` key the legacy pageview beacon already used, so\r\n *   existing sessions carry over unchanged.\r\n * - `visitorId`: first-party persistent UUID v4 in localStorage\r\n *   (`micdrop_visitor_id`), created on first read and REUSED thereafter. Never\r\n *   regenerated on read (a literal refresh must not rotate identity). Replaced\r\n *   only when missing or not a valid UUID. Consent-gated: withheld while a host\r\n *   consent signal exists ungranted (beacons then fall back to sessionId-only).\r\n *\r\n * Storage goes through the svelte-components canonical helpers, which are\r\n * SSR-safe and no-op when storage is blocked (sandboxed iframe) — a blocked\r\n * store just means no persistent identity, never a thrown error.\r\n */\r\nimport {\r\n  getLocalStorage,\r\n  setLocalStorage,\r\n  getSessionStorage,\r\n  setSessionStorage,\r\n} from '@getmicdrop/svelte-components';\r\nimport { isConsentGranted } from './consent.js';\r\n\r\nconst SESSION_ID_KEY = 'micdrop_session_id';\r\nconst VISITOR_ID_KEY = 'micdrop_visitor_id';\r\n\r\n// RFC 4122 v4 shape — the validity gate for a stored id. A stored value that\r\n// isn't a well-formed v4 UUID is treated as corrupt and replaced.\r\nconst UUID_V4 =\r\n  /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\r\n\r\nfunction isUuidV4(value: unknown): value is string {\r\n  return typeof value === 'string' && UUID_V4.test(value);\r\n}\r\n\r\n/**\r\n * Generate a UUID v4. Prefers the platform `crypto.randomUUID` (the same source\r\n * svelte-components uses); falls back to a `getRandomValues`-seeded v4 for the\r\n * rare embed host without it, and finally to a Math.random v4 so a beacon on a\r\n * legacy host still gets a well-formed id.\r\n */\r\nfunction generateUuidV4(): string {\r\n  const cryptoObj: Crypto | undefined =\r\n    typeof crypto !== 'undefined' ? crypto : undefined;\r\n  if (cryptoObj?.randomUUID) return cryptoObj.randomUUID();\r\n\r\n  const bytes = new Uint8Array(16);\r\n  if (cryptoObj?.getRandomValues) {\r\n    cryptoObj.getRandomValues(bytes);\r\n  } else {\r\n    for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\r\n  }\r\n  bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4\r\n  bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10xx\r\n  const hex: string[] = [];\r\n  for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, '0'));\r\n  return (\r\n    `${hex[0]}${hex[1]}${hex[2]}${hex[3]}-${hex[4]}${hex[5]}-${hex[6]}${hex[7]}-` +\r\n    `${hex[8]}${hex[9]}-${hex[10]}${hex[11]}${hex[12]}${hex[13]}${hex[14]}${hex[15]}`\r\n  );\r\n}\r\n\r\n/**\r\n * Per-tab session id. Created once and reused for the tab's lifetime. Reuses\r\n * the historical `micdrop_session_id` key so in-flight sessions are unbroken.\r\n */\r\nexport function getSessionId(): string {\r\n  let id = getSessionStorage<string>(SESSION_ID_KEY);\r\n  if (!id) {\r\n    id = generateUuidV4();\r\n    setSessionStorage(SESSION_ID_KEY, id);\r\n  }\r\n  return id;\r\n}\r\n\r\n/**\r\n * First-party persistent visitor id, or `null` when consent is required and not\r\n * yet granted (beacons then carry sessionId only). Created on first *allowed*\r\n * read and reused thereafter; a corrupt stored value is replaced.\r\n */\r\nexport function getVisitorId(): string | null {\r\n  if (!isConsentGranted()) return null;\r\n\r\n  const stored = getLocalStorage<string>(VISITOR_ID_KEY);\r\n  if (isUuidV4(stored)) return stored;\r\n\r\n  const id = generateUuidV4();\r\n  setLocalStorage(VISITOR_ID_KEY, id);\r\n  return id;\r\n}\r\n\r\n/** Exposed for tests + the storage keys other tracking modules assert against. */\r\nexport const _identityKeys = { SESSION_ID_KEY, VISITOR_ID_KEY } as const;\r\n","/**\r\n * First-party attribution store (MISSION-TRUTH C2).\r\n *\r\n * Every order-completing call stamps an `attribution` object read from HERE —\r\n * never from `window.location`, because the standalone checkout route drops the\r\n * query params. The store is updated on every beacon and follows the\r\n * LAST NON-DIRECT TOUCH rule:\r\n *\r\n *   - A beacon carrying an explicit non-direct utm (or a fresh external\r\n *     referrer) OVERWRITES the store.\r\n *   - A direct / internal touch NEVER overwrites a prior marketing touch; it\r\n *     only seeds the store when nothing has been recorded yet.\r\n *   - So `direct` appears in attribution only when the session never had a\r\n *     non-direct touch.\r\n *\r\n * Persisted in sessionStorage (per-tab, matches sessionId scope) via the SC\r\n * storage canonical — SSR-safe, no-op when storage is blocked (a blocked store\r\n * just means the live host-context fallback is used at read time).\r\n */\r\nimport {\r\n  getSessionStorage,\r\n  setSessionStorage,\r\n} from '@getmicdrop/svelte-components';\r\nimport { isMarketingUtm, type UtmSet } from './normalize.js';\r\nimport { resolveHostContext, type HostContext } from './context.js';\r\nimport { getSessionId, getVisitorId } from './identity.js';\r\n\r\nconst ATTRIBUTION_KEY = 'micdrop_attribution';\r\n\r\ninterface StoredTouch {\r\n  utm: UtmSet;\r\n  referrer: string;\r\n  /** true = a marketing touch that direct touches must not overwrite. */\r\n  marketing: boolean;\r\n}\r\n\r\n/** The additive object stamped onto every order-completing call. */\r\nexport interface AttributionPayload {\r\n  sessionId: string;\r\n  visitorId: string | null;\r\n  utmSource: string;\r\n  utmMedium: string;\r\n  utmCampaign: string;\r\n  utmContent: string;\r\n  utmTerm: string;\r\n  referrer: string;\r\n}\r\n\r\n/**\r\n * A referrer counts as \"external\" when it has a host that differs from the host\r\n * page's own host. In the light-DOM embed the page is the host page; in iframe\r\n * mode `pageUrl` is the forwarded host page. Same-host (internal) navigations\r\n * never qualify as a marketing touch.\r\n */\r\nfunction isExternalReferrer(referrer: string, pageUrl: string): boolean {\r\n  if (!referrer || !pageUrl) return false;\r\n  // `pageUrl` is the host page ONLY when known (top-level document, or the\r\n  // forwarded host url in iframe mode) — resolveHostContext leaves it empty for\r\n  // an unforwarded iframe, where we can't tell internal from external and so\r\n  // must not conjure a marketing touch (the early return above). Never fall\r\n  // back to window.location here: in a frame that's Micdrop's host, not the\r\n  // venue's.\r\n  try {\r\n    const refHost = new URL(referrer).host;\r\n    const ownHost = new URL(pageUrl).host;\r\n    return !!refHost && !!ownHost && refHost !== ownHost;\r\n  } catch {\r\n    return false;\r\n  }\r\n}\r\n\r\n/** A touch is \"marketing\" when it has a non-direct utm OR a fresh external referrer. */\r\nfunction isMarketingTouch(ctx: HostContext): boolean {\r\n  return (\r\n    isMarketingUtm(ctx.utm) || isExternalReferrer(ctx.referrer, ctx.pageUrl)\r\n  );\r\n}\r\n\r\nfunction readStore(): StoredTouch | null {\r\n  const raw = getSessionStorage<StoredTouch>(ATTRIBUTION_KEY);\r\n  if (!raw || !raw.utm || typeof raw.utm.utmSource !== 'string') return null;\r\n  return raw;\r\n}\r\n\r\n/**\r\n * Record the current host context as a touch, applying the last-non-direct-touch\r\n * rule. Called on every beacon. Idempotent for repeated direct touches.\r\n */\r\nexport function recordTouch(ctx: HostContext = resolveHostContext()): void {\r\n  const marketing = isMarketingTouch(ctx);\r\n  const existing = readStore();\r\n\r\n  // Direct/internal touch never overwrites a recorded touch — it only seeds an\r\n  // empty store.\r\n  if (!marketing && existing) return;\r\n\r\n  setSessionStorage(ATTRIBUTION_KEY, {\r\n    utm: ctx.utm,\r\n    referrer: ctx.referrer,\r\n    marketing,\r\n  } satisfies StoredTouch);\r\n}\r\n\r\n/**\r\n * Build the attribution object for an order-completing call. Reads the stored\r\n * touch (falling back to the live host context if nothing was recorded — e.g.\r\n * storage blocked) and attaches the current session + visitor identity.\r\n * `visitorId` is null while consent is withheld (C5).\r\n */\r\nexport function getAttribution(): AttributionPayload {\r\n  const stored = readStore();\r\n  const touch: Pick<StoredTouch, 'utm' | 'referrer'> =\r\n    stored ?? resolveHostContext();\r\n\r\n  return {\r\n    sessionId: getSessionId(),\r\n    visitorId: getVisitorId(),\r\n    utmSource: touch.utm.utmSource,\r\n    utmMedium: touch.utm.utmMedium,\r\n    utmCampaign: touch.utm.utmCampaign,\r\n    utmContent: touch.utm.utmContent,\r\n    utmTerm: touch.utm.utmTerm,\r\n    referrer: touch.referrer || '',\r\n  };\r\n}\r\n\r\n/** Test-only key accessor. */\r\nexport const _attributionKey = ATTRIBUTION_KEY;\r\n","// @fetch-escape: fire-and-forget funnel beacons — raw keepalive POST, response\r\n// ignored. apiPost would parse JSON on the empty 2xx body and log a false error,\r\n// and a beacon must survive the visitor navigating away (keepalive).\r\n/**\r\n * Funnel beacons (MISSION-TRUTH C1).\r\n *\r\n * One sender fires all six funnel moments — widget_load, list_view,\r\n * event_view, add_to_cart, checkout_started, purchase — to the extended\r\n * pageview endpoint. The payload is ADDITIVE: the old event_view shape keeps\r\n * working when the backend (MIC-1255) hasn't shipped the new fields yet.\r\n *\r\n * Every beacon also refreshes the first-party attribution store (last\r\n * non-direct touch, C2) so an order completing later can stamp the right\r\n * source even after the checkout route drops the query params.\r\n *\r\n * Fire-and-forget: a tracking failure must NEVER affect the embedded widget, so\r\n * errors are swallowed and the raw `keepalive` fetch is intentional (a beacon\r\n * must complete even if the visitor navigates away immediately).\r\n */\r\nimport {\r\n  createLogger,\r\n  getSessionStorage,\r\n  setSessionStorage,\r\n} from '@getmicdrop/svelte-components';\r\nimport { getPublicBaseUrl } from '../api/client.js';\r\nimport {\r\n  resolveHostContext,\r\n  getWidgetId,\r\n  getVenueId,\r\n  getDeviceType,\r\n} from './context.js';\r\nimport { getSessionId, getVisitorId } from './identity.js';\r\nimport { recordTouch } from './attribution-store.js';\r\n\r\nconst logger = createLogger('tracking');\r\n\r\nexport type BeaconEventType =\r\n  | 'widget_load'\r\n  | 'list_view'\r\n  | 'event_view'\r\n  | 'add_to_cart'\r\n  | 'checkout_started'\r\n  | 'purchase';\r\n\r\n/** Moments that are conversions — never deduped (each is a distinct funnel step). */\r\nconst NEVER_DEDUP: ReadonlySet<BeaconEventType> = new Set([\r\n  'add_to_cart',\r\n  'checkout_started',\r\n  'purchase',\r\n]);\r\n\r\nconst DEDUP_KEY = 'micdrop_tracked_beacons';\r\n// Cap the per-session dedup ledger so a long browsing session (many events /\r\n// list views, each a distinct key) can't grow the sessionStorage array without\r\n// bound. Oldest keys age out FIFO — re-firing a long-ago-seen view is a\r\n// harmless duplicate the backend already tolerates.\r\nconst DEDUP_LEDGER_MAX = 300;\r\n\r\ninterface BeaconOptions {\r\n  /** Null for widget_load / list_view (no specific entity yet). */\r\n  eventId?: string | number | null;\r\n  /**\r\n   * Per-instance widget id. Threaded as a prop from the mounting widget so two\r\n   * <micdrop-calendar> embeds on one page don't collapse into one view (the\r\n   * dedup key keys on it). Falls back to the init-time global context when the\r\n   * caller doesn't pass one (auto-mount single-widget / standalone entries).\r\n   */\r\n  widgetId?: string | null;\r\n  /** Per-instance venue id; same fallback semantics as widgetId. */\r\n  venueId?: string | number | null;\r\n}\r\n\r\n/**\r\n * Dedup key per MISSION-TRUTH C1:\r\n *   eventType:eventId:widgetId:normUtmSource:normUtmCampaign:sessionId\r\n * with pageUrl standing in for a null widgetId (so two widgets on one page\r\n * aren't collapsed into a single view).\r\n */\r\nfunction dedupKey(\r\n  eventType: BeaconEventType,\r\n  eventId: string | number | null,\r\n  widgetId: string | null,\r\n  utmSource: string,\r\n  utmCampaign: string,\r\n  sessionId: string,\r\n  pageUrl: string\r\n): string {\r\n  // `||` (not `??`): an empty-string widgetId must fall back to pageUrl too, so\r\n  // two id-less widgets on one page don't share a dedup bucket.\r\n  const widgetPart = widgetId || `url:${pageUrl}`;\r\n  return [\r\n    eventType,\r\n    eventId ?? '',\r\n    widgetPart,\r\n    utmSource,\r\n    utmCampaign,\r\n    sessionId,\r\n  ].join(':');\r\n}\r\n\r\n/**\r\n * Coerce an id to a finite number, or null. A non-numeric value (e.g. a venue\r\n * *slug* passed as `venueId` on a demo embed) becomes null rather than a `NaN`\r\n * that would serialize to a misleading value — the backend keys on the other\r\n * dimensions in that case.\r\n */\r\nfunction toNumericOrNull(\r\n  value: string | number | null | undefined\r\n): number | null {\r\n  if (value == null || value === '') return null;\r\n  const n = Number(value);\r\n  return Number.isFinite(n) ? n : null;\r\n}\r\n\r\nfunction alreadySent(key: string): boolean {\r\n  const sent = getSessionStorage<string[]>(DEDUP_KEY, []) ?? [];\r\n  if (sent.includes(key)) return true;\r\n  // Append, keeping only the most recent DEDUP_LEDGER_MAX keys (FIFO).\r\n  const next = [...sent, key];\r\n  setSessionStorage(\r\n    DEDUP_KEY,\r\n    next.length > DEDUP_LEDGER_MAX ? next.slice(-DEDUP_LEDGER_MAX) : next\r\n  );\r\n  return false;\r\n}\r\n\r\n/**\r\n * Fire one funnel beacon. Resolves host context once, refreshes the attribution\r\n * store, dedups (except conversions), then posts additively.\r\n */\r\nexport async function trackBeacon(\r\n  eventType: BeaconEventType,\r\n  {\r\n    eventId = null,\r\n    widgetId: widgetIdArg,\r\n    venueId: venueIdArg,\r\n  }: BeaconOptions = {}\r\n): Promise<void> {\r\n  if (typeof window === 'undefined') return;\r\n\r\n  const ctx = resolveHostContext();\r\n  // Keep the attribution store fresh on every touch — even a deduped view still\r\n  // represents the visitor being here now.\r\n  recordTouch(ctx);\r\n\r\n  const sessionId = getSessionId();\r\n  // Prefer the per-instance id passed by the mounting widget; fall back to the\r\n  // init-time global context.\r\n  const widgetId = widgetIdArg !== undefined ? widgetIdArg : getWidgetId();\r\n\r\n  if (!NEVER_DEDUP.has(eventType)) {\r\n    const key = dedupKey(\r\n      eventType,\r\n      eventId,\r\n      widgetId,\r\n      ctx.utm.utmSource,\r\n      ctx.utm.utmCampaign,\r\n      sessionId,\r\n      ctx.pageUrl\r\n    );\r\n    if (alreadySent(key)) return;\r\n  }\r\n\r\n  const venueId = venueIdArg !== undefined ? venueIdArg : getVenueId();\r\n  const body = {\r\n    eventType,\r\n    eventId: toNumericOrNull(eventId),\r\n    venueId: toNumericOrNull(venueId),\r\n    widgetId,\r\n    utmSource: ctx.utm.utmSource,\r\n    utmMedium: ctx.utm.utmMedium,\r\n    utmCampaign: ctx.utm.utmCampaign,\r\n    utmContent: ctx.utm.utmContent,\r\n    utmTerm: ctx.utm.utmTerm,\r\n    sessionId,\r\n    visitorId: getVisitorId(),\r\n    deviceType: getDeviceType(),\r\n    referrer: ctx.referrer,\r\n    pageUrl: ctx.pageUrl,\r\n  };\r\n\r\n  try {\r\n    await fetch(`${getPublicBaseUrl()}/track/pageview`, {\r\n      method: 'POST',\r\n      headers: { 'Content-Type': 'application/json' },\r\n      body: JSON.stringify(body),\r\n      keepalive: true,\r\n    });\r\n  } catch (err) {\r\n    logger.error(`Beacon '${eventType}' failed:`, err);\r\n  }\r\n}\r\n\r\n/** Widget mounted on the host page (no entity yet). */\r\nexport const trackWidgetLoad = (\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> => trackBeacon('widget_load', { widgetId, venueId });\r\n\r\n/** Visitor is looking at the calendar/list of events. */\r\nexport const trackListView = (\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> => trackBeacon('list_view', { widgetId, venueId });\r\n\r\n/** Visitor opened a specific event's detail page. */\r\nexport const trackEventView = (\r\n  eventId: string | number,\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> => trackBeacon('event_view', { eventId, widgetId, venueId });\r\n\r\n/** Visitor added tickets to the cart (cart created). */\r\nexport const trackAddToCart = (\r\n  eventId: string | number,\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> => trackBeacon('add_to_cart', { eventId, widgetId, venueId });\r\n\r\n/** Visitor opened the checkout UI. */\r\nexport const trackCheckoutStarted = (\r\n  eventId: string | number,\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> =>\r\n  trackBeacon('checkout_started', { eventId, widgetId, venueId });\r\n\r\n/** Order completed. */\r\nexport const trackPurchase = (\r\n  eventId: string | number,\r\n  widgetId?: string | null,\r\n  venueId?: string | number | null\r\n): Promise<void> => trackBeacon('purchase', { eventId, widgetId, venueId });\r\n\r\n/** Test-only reset of the dedup ledger key. */\r\nexport const _dedupKeyForTests = DEDUP_KEY;\r\n","import { AppError } from '@getmicdrop/svelte-components';\r\n/**\r\n * Orders API\r\n *\r\n * Functions for managing orders, payments, and reservations\r\n * in the public checkout flow.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nconst logger = createLogger('VC');\r\nimport {\r\n  getPublicBaseUrl,\r\n  getOrdersV2Url,\r\n  simpleFetch,\r\n  apiPost,\r\n  apiGet,\r\n} from './client.js';\r\nimport { parseCart } from './transformers/cart.js';\r\nimport { getAttribution } from '../tracking/index.js';\r\nimport { normalizeUtmValue, DIRECT_SOURCE } from '../tracking/normalize.js';\r\nimport type {\r\n  PaymentIntentResponse,\r\n  CompleteReservationResponse,\r\n  CancelReservationResponse,\r\n  CreateOrderResponse,\r\n  ValidatePaymentRequest,\r\n  ValidatePaymentResponse,\r\n  ExtendSessionResponse,\r\n  SessionStatus,\r\n  Order,\r\n} from './types.js';\r\n\r\n/**\r\n * Create a payment intent for the cart\r\n *\r\n * This initiates the Stripe payment flow by creating a PaymentIntent\r\n * on the backend. The response includes the client_secret needed\r\n * for Stripe Elements.\r\n *\r\n * @param cartId - The cart/order UUID\r\n * @param quantities - Map of ticketId -> quantity\r\n * @param donationAmounts - Map of ticketId -> donation amount in dollars (for type=2 tickets)\r\n * @returns Payment intent data including client_secret, or null on error\r\n */\r\nexport async function createPaymentIntent(\r\n  cartId: string,\r\n  quantities: Record<string | number, number>,\r\n  donationAmounts?: Record<string | number, number>\r\n): Promise<PaymentIntentResponse | null> {\r\n  try {\r\n    const apiResult = await apiPost<PaymentIntentResponse>(\r\n      `${getOrdersV2Url()}/cart/${cartId}/payment-intent`,\r\n      {\r\n        productQuantities: quantities,\r\n        ...(donationAmounts && Object.keys(donationAmounts).length > 0\r\n          ? { donationAmounts }\r\n          : {}),\r\n        // Order attribution (MISSION-TRUTH C2) — additive; ignored by a backend\r\n        // that hasn't shipped MIC-1255 yet. Free orders finalize via this\r\n        // payment-intent pre-submit, so this covers the free-order path too.\r\n        attribution: getAttribution(),\r\n      }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Payment intent creation failed:', apiResult.error);\r\n      throw new AppError(\r\n        apiResult.error || 'Failed to create payment intent',\r\n        'lib/api/orders/createPaymentIntent'\r\n      );\r\n    }\r\n\r\n    logger.debug('Payment intent created:', apiResult.data);\r\n    return apiResult.data!;\r\n  } catch (error) {\r\n    logger.error('createPaymentIntent error:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Fetch an existing cart by UUID (cross-device pre-fill — §1.3).\r\n *\r\n * Returns the server's authoritative view of a cart so a second device\r\n * visiting the tickets page can see the in-progress reservation it created\r\n * on another device. Returns `null` if:\r\n *   - the cart no longer exists (404)\r\n *   - the cart belongs to a different event than `expectedEventID` (when\r\n *     supplied) — we don't want to mix carts across events\r\n *   - the cart status is no longer `reserved` / `active` (e.g. expired,\r\n *     completed, abandoned) — caller should treat the local cookie as stale\r\n *   - any network/decode failure (caller falls back to localStorage only)\r\n *\r\n * Returned shape matches the orders-service `GET /v2Public/cart/{uuid}`\r\n * response: a Cart model with embedded Reservations.\r\n */\r\nexport interface CartReservationView {\r\n  ticketID: number;\r\n  quantity: number;\r\n  priceAtReservation: number;\r\n  status: string;\r\n}\r\nexport interface CartView {\r\n  uuid: string;\r\n  eventID: number;\r\n  status: string;\r\n  expiresAt: string;\r\n  reservations: CartReservationView[];\r\n}\r\n\r\nexport async function getCartByUUID(\r\n  cartUUID: string,\r\n  expectedEventID?: string | number\r\n): Promise<CartView | null> {\r\n  if (!cartUUID) return null;\r\n  try {\r\n    const apiResult = await apiGet<unknown>(\r\n      `${getOrdersV2Url()}/cart/${cartUUID}`\r\n    );\r\n    if (!apiResult.success) {\r\n      // 404 / 410 / 5xx — caller treats as stale\r\n      return null;\r\n    }\r\n    // Wire->domain normalization (PascalCase/camelCase reconciliation, numeric\r\n    // coercion, reservation sub-parse) lives in parseCart — byte-identical to\r\n    // the inline mapper this replaced. Staleness/event-mismatch policy below\r\n    // stays here because it is a caller decision, not normalization.\r\n    const { uuid, eventID, status, expiresAt, reservations } = parseCart(\r\n      apiResult.data!\r\n    );\r\n    if (status !== 'reserved' && status !== 'active') {\r\n      // stale cart row — caller clears the cookie\r\n      return null;\r\n    }\r\n    if (expectedEventID !== undefined && eventID !== Number(expectedEventID)) {\r\n      // cart belongs to a different event — don't mix\r\n      return null;\r\n    }\r\n    return { uuid, eventID, status, expiresAt, reservations };\r\n  } catch (err) {\r\n    logger.error('getCartByUUID error:', err);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Update cart quantities after the cart already exists.\r\n *\r\n * Replaces all reservations on the cart with the new quantities.\r\n * The orders-service handler releases old reservations (returning\r\n * inventory) and creates new ones (decrementing inventory) atomically.\r\n *\r\n * Use this when the user changes ticket counts AFTER the initial\r\n * cart was created via initiateOrder. The cart UUID is preserved,\r\n * so the timer and extension state stay intact.\r\n *\r\n * @returns true on success, false on failure\r\n */\r\nexport async function updateCartQuantities(\r\n  cartId: string,\r\n  quantities: Record<string | number, number>,\r\n  donationAmounts?: Record<string | number, number>\r\n): Promise<boolean> {\r\n  try {\r\n    // Convert string keys to numbers (the orders-service handler\r\n    // unmarshals into map[uint]int).\r\n    const numericQuantities: Record<number, number> = {};\r\n    for (const [k, v] of Object.entries(quantities)) {\r\n      const n = typeof k === 'number' ? k : parseInt(k, 10);\r\n      if (!Number.isNaN(n) && v > 0) numericQuantities[n] = v;\r\n    }\r\n    const numericDonations: Record<number, number> = {};\r\n    if (donationAmounts) {\r\n      for (const [k, v] of Object.entries(donationAmounts)) {\r\n        const n = typeof k === 'number' ? k : parseInt(k, 10);\r\n        if (!Number.isNaN(n) && v > 0) numericDonations[n] = v;\r\n      }\r\n    }\r\n    // @fetch-escape: status-only endpoint — PUT /cart/:id returns an empty 2xx (no JSON body)\r\n    // on success; the canonical apiPut runs response.json() unconditionally on 2xx and would\r\n    // throw on the empty body, mis-reporting a successful cart update as a failure. Migrate once\r\n    // the client tolerates 204/empty bodies.\r\n    const response = await fetch(`${getOrdersV2Url()}/cart/${cartId}`, {\r\n      method: 'PUT',\r\n      headers: { 'Content-Type': 'application/json' },\r\n      credentials: 'include',\r\n      body: JSON.stringify({\r\n        quantities: numericQuantities,\r\n        ...(Object.keys(numericDonations).length > 0\r\n          ? { donationAmounts: numericDonations }\r\n          : {}),\r\n      }),\r\n    });\r\n    if (!response.ok) {\r\n      const errorData = await response.json().catch(() => ({}));\r\n      logger.error('Cart update failed:', errorData);\r\n      return false;\r\n    }\r\n    return true;\r\n  } catch (err) {\r\n    logger.error('updateCartQuantities error:', err);\r\n    return false;\r\n  }\r\n}\r\n\r\n/**\r\n * Complete reservation after successful payment\r\n *\r\n * Called after Stripe confirms the payment to finalize the order\r\n * and generate tickets.\r\n *\r\n * @param orderUuid - The order UUID\r\n * @returns Success status and message\r\n */\r\nexport async function completeReservation(\r\n  orderUuid: string\r\n): Promise<CompleteReservationResponse> {\r\n  try {\r\n    const apiResult = await apiPost<{ message?: string }>(\r\n      `${getPublicBaseUrl()}/orders/complete/${orderUuid}`\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to complete reservation',\r\n      };\r\n    }\r\n\r\n    return {\r\n      success: true,\r\n      message: apiResult.data?.message,\r\n    };\r\n  } catch (error) {\r\n    logger.error('Error completing reservation:', error);\r\n    return { success: false, error: 'Network error completing reservation' };\r\n  }\r\n}\r\n\r\n/**\r\n * Cancel reservation and release tickets back to inventory\r\n *\r\n * Called when user abandons checkout or session expires.\r\n *\r\n * @param orderUuid - The order UUID\r\n * @returns Success status and message\r\n */\r\nexport async function cancelReservation(\r\n  orderUuid: string\r\n): Promise<CancelReservationResponse> {\r\n  try {\r\n    const apiResult = await apiPost<{ message?: string }>(\r\n      `${getPublicBaseUrl()}/orders/cancel/${orderUuid}`\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to cancel reservation',\r\n      };\r\n    }\r\n\r\n    return {\r\n      success: true,\r\n      message: apiResult.data?.message,\r\n    };\r\n  } catch (error) {\r\n    logger.error('Error cancelling reservation:', error);\r\n    return { success: false, error: 'Network error cancelling reservation' };\r\n  }\r\n}\r\n\r\n/**\r\n * Create a new order/cart\r\n *\r\n * This creates an empty order that can be used for checkout.\r\n * The order UUID is used for all subsequent operations.\r\n *\r\n * @param eventId - The event ID\r\n * @param promoCode - Optional promo code to apply\r\n * @returns The order UUID, or null on error\r\n */\r\nexport async function createOrder(\r\n  eventId: string | number,\r\n  promoCode?: string\r\n): Promise<CreateOrderResponse | null> {\r\n  try {\r\n    const apiResult = await apiPost<CreateOrderResponse>(\r\n      `${getPublicBaseUrl()}/orders/create`,\r\n      // attribution (MISSION-TRUTH C2) rides on cart-create additively.\r\n      { eventID: eventId, promoCode, attribution: getAttribution() }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Create order failed:', apiResult.error);\r\n      return null;\r\n    }\r\n\r\n    return apiResult.data!;\r\n  } catch (error) {\r\n    logger.error('createOrder error:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Get order details (public, no auth required)\r\n *\r\n * Fetches the order details for displaying on the success page.\r\n *\r\n * @param orderId - The order UUID or ID\r\n * @returns The order details, or null on error\r\n */\r\nexport async function getOrder(orderId: string): Promise<Order | null> {\r\n  return simpleFetch<Order>(`${getPublicBaseUrl()}/orders/${orderId}`);\r\n}\r\n\r\n/**\r\n * Validate payment intent and complete the order\r\n *\r\n * This is an alternative to completeReservation that accepts\r\n * additional payment details. Used by micdrop-frontend.\r\n *\r\n * @param cartId - The cart/order UUID\r\n * @param payload - Payment validation payload\r\n * @returns Validation result\r\n */\r\nexport async function validatePaymentIntent(\r\n  cartId: string,\r\n  payload: ValidatePaymentRequest\r\n): Promise<ValidatePaymentResponse | null> {\r\n  try {\r\n    const apiResult = await apiPost<{\r\n      success?: boolean;\r\n      status?: string;\r\n      orderUUID?: string;\r\n      uuid?: string;\r\n      // Fail-closed FLOOR flags — the backend gate sets one (with success:false)\r\n      // when the event was canceled/postponed mid-purchase and the charge was\r\n      // NOT captured. They ride in the 200 response body, so they must be read\r\n      // off `data` here and FORWARDED — Checkout.svelte keys the\r\n      // EventUnavailableModal off response.eventCanceled / response.eventPostponed.\r\n      eventCanceled?: boolean;\r\n      eventPostponed?: boolean;\r\n      // Order attribution (MISSION-TRUTH C2) — additive; finalize wins over the\r\n      // cart-create stamp on conflict, backend-side.\r\n    }>(`${getOrdersV2Url()}/validatePaymentIntent/${cartId}`, {\r\n      ...payload,\r\n      attribution: getAttribution(),\r\n    });\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Payment validation failed:', apiResult.error);\r\n      return {\r\n        success: false,\r\n        status: 'failed',\r\n        error: apiResult.error || 'Payment validation failed',\r\n      };\r\n    }\r\n\r\n    const result = apiResult.data!;\r\n\r\n    // FAIL-CLOSED FLOOR: a 200 body carrying eventCanceled/eventPostponed means\r\n    // the finalize was rejected and no charge was captured. Forward the flags\r\n    // (do NOT coerce to \"Payment succeeded\") so the checkout raises the\r\n    // charge-aware modal instead of navigating to the success page.\r\n    if (result.eventCanceled || result.eventPostponed) {\r\n      return {\r\n        success: false,\r\n        status: 'failed',\r\n        eventCanceled: result.eventCanceled,\r\n        eventPostponed: result.eventPostponed,\r\n      };\r\n    }\r\n\r\n    return {\r\n      success: true,\r\n      status: result.status || 'Payment succeeded',\r\n      orderUUID: result.orderUUID || result.uuid,\r\n    };\r\n  } catch (error) {\r\n    logger.error('validatePaymentIntent error:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Extend the checkout session by 15 minutes\r\n *\r\n * Users get a limited number of extensions (typically 2-3).\r\n *\r\n * @param orderUuid - The order UUID\r\n * @returns Extension result with new expiry time\r\n */\r\nexport async function extendCheckoutSession(\r\n  orderUuid: string\r\n): Promise<ExtendSessionResponse> {\r\n  try {\r\n    const apiResult = await apiPost<{\r\n      newExpiryTime?: string;\r\n      remainingExtensions?: number;\r\n    }>(`${getPublicBaseUrl()}/orders/extend-session`, { orderUuid });\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to extend session',\r\n        statusCode: apiResult.statusCode,\r\n      };\r\n    }\r\n\r\n    const result = apiResult.data!;\r\n    return {\r\n      success: true,\r\n      newExpiryTime: result.newExpiryTime,\r\n      remainingExtensions: result.remainingExtensions,\r\n    };\r\n  } catch (error) {\r\n    logger.error('Error extending checkout session:', error);\r\n    return { success: false, error: 'Network error extending session' };\r\n  }\r\n}\r\n\r\n/**\r\n * Get current session status including expiry time\r\n *\r\n * Used to display countdown timer and check if extensions are available.\r\n *\r\n * @param orderUuid - The order UUID\r\n * @returns Session status including expiry time\r\n */\r\nexport async function getSessionStatus(\r\n  orderUuid: string\r\n): Promise<SessionStatus> {\r\n  try {\r\n    const apiResult = await apiGet<SessionStatus>(\r\n      `${getPublicBaseUrl()}/orders/session/${orderUuid}`\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        error: apiResult.error || 'No active session found',\r\n        notFound: apiResult.statusCode === 404,\r\n      };\r\n    }\r\n\r\n    const result = apiResult.data!;\r\n    return {\r\n      expiresAt: result.expiresAt,\r\n      extensionCount: result.extensionCount,\r\n      remainingExtensions: result.remainingExtensions,\r\n      canExtend: result.canExtend,\r\n      reservationCount: result.reservationCount,\r\n      eventStatus: result.eventStatus,\r\n    };\r\n  } catch (error) {\r\n    logger.error('Error getting session status:', error);\r\n    return { error: 'Network error getting session status' };\r\n  }\r\n}\r\n\r\n/**\r\n * Initiate a new order (alias for createOrder)\r\n *\r\n * This function provides backwards compatibility with micdrop-frontend.\r\n * It accepts the same parameters as the legacy initiateOrder function.\r\n *\r\n * @param cartData - Object containing eventID and optional quantities/promoCode\r\n * @returns The order UUID, or null on error\r\n */\r\nexport async function initiateOrder(\r\n  cartData: {\r\n    eventID: string | number;\r\n    promoCode?: string;\r\n    quantities?: Record<string | number, number>;\r\n  } = { eventID: '' }\r\n): Promise<string | null> {\r\n  try {\r\n    const apiResult = await apiPost<{ uuid?: string }>(\r\n      `${getPublicBaseUrl()}/orders/create`,\r\n      // attribution (MISSION-TRUTH C2) rides on cart-create additively.\r\n      { ...cartData, attribution: getAttribution() }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Order initiation failed:', apiResult.error);\r\n      return null;\r\n    }\r\n\r\n    return apiResult.data?.uuid ?? null;\r\n  } catch (error) {\r\n    logger.error('initiateOrder error:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Track UTM source for analytics\r\n *\r\n * Records the traffic source (utm_source parameter) for marketing analytics.\r\n *\r\n * @param venueId - The venue ID\r\n * @returns Promise that resolves when tracking is complete\r\n */\r\nexport async function trackUTMSource(venueId: string | number): Promise<void> {\r\n  if (typeof window === 'undefined') return;\r\n\r\n  const urlParams = new URLSearchParams(window.location.search);\r\n  // Normalized at write time; empty resolves to the ONE canonical default\r\n  // `direct` (kills the historical `Direct`/`''`/`direct` split).\r\n  const utmSource =\r\n    normalizeUtmValue(urlParams.get('utm_source')) || DIRECT_SOURCE;\r\n\r\n  try {\r\n    // @fetch-escape: fire-and-forget UTM beacon — GET with no response body consumed; simpleFetch would parse JSON on empty 200 and log false-positive errors\r\n    await fetch(\r\n      `${getPublicBaseUrl()}/utm/${venueId}/${encodeURIComponent(utmSource)}`\r\n    );\r\n  } catch (error) {\r\n    logger.error('UTM tracking failed:', error);\r\n  }\r\n}\r\n","/**\r\n * Promo Codes API\r\n *\r\n * Functions for validating and checking promo codes\r\n * in the public checkout flow.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nconst logger = createLogger('VC');\r\nimport { apiGet, apiPost, getOrdersV2Url } from './client.js';\r\nimport type { PromoValidationResponse, HasPromoCodesResponse } from './types.js';\r\n\r\nconst ORDERS_V2_PUBLIC = () => getOrdersV2Url();\r\n\r\n/**\r\n * Validate a promo code for an event\r\n *\r\n * Checks if a promo code is valid and returns its effects:\r\n * - Discount amount and type\r\n * - Hidden ticket reveal\r\n *\r\n * @param eventId - The event ID\r\n * @param code - The promo code to validate\r\n * @returns Validation result with discount info\r\n */\r\nexport async function validatePromoCode(\r\n  eventId: string | number,\r\n  code: string\r\n): Promise<PromoValidationResponse> {\r\n  try {\r\n    if (!code || !code.trim()) {\r\n      return { valid: false, error: 'Promo code is required' };\r\n    }\r\n\r\n    // API uses GET with code in URL path\r\n    const encodedCode = encodeURIComponent(code.trim());\r\n    const apiResult = await apiGet<PromoValidationResponse>(\r\n      `/promo-codes/validate/${eventId}/${encodedCode}`\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      // 404 = invalid code, other errors are server issues\r\n      if (apiResult.statusCode === 404) {\r\n        return { valid: false, error: 'Invalid promo code' };\r\n      }\r\n      return { valid: false, error: 'Failed to validate code' };\r\n    }\r\n\r\n    const result = apiResult.data!;\r\n    return {\r\n      valid: result.valid ?? true,\r\n      revealHiddenTickets: result.revealHiddenTickets,\r\n      revealTicketIds: result.revealTicketIds,\r\n      provideDiscount: result.provideDiscount,\r\n      discountType: result.discountType,\r\n      amount: result.amount,\r\n      code: result.code || code,\r\n    };\r\n  } catch (error) {\r\n    logger.error('Error validating promo code:', error);\r\n    return { valid: false, error: 'Network error validating code' };\r\n  }\r\n}\r\n\r\n/**\r\n * Check if promo codes are available for an event\r\n *\r\n * Used to conditionally show/hide the promo code input field.\r\n *\r\n * @param eventId - The event ID\r\n * @returns Whether promo codes exist for this event\r\n */\r\nexport async function hasPromoCodes(eventId: string | number): Promise<boolean> {\r\n  try {\r\n    const apiResult = await apiGet<HasPromoCodesResponse>(\r\n      `/promo-codes/check/${eventId}`\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      // If endpoint doesn't exist or errors, default to showing the input\r\n      return true;\r\n    }\r\n\r\n    return apiResult.data!.hasPromoCodes === true;\r\n  } catch (error) {\r\n    logger.error('Error checking promo codes availability:', error);\r\n    // Default to showing promo input if we can't check\r\n    return true;\r\n  }\r\n}\r\n\r\n/**\r\n * Apply a promo code to a cart\r\n *\r\n * This updates the cart with the promo code discount.\r\n *\r\n * @param cartId - The cart UUID\r\n * @param code - The promo code to apply\r\n * @returns Success status\r\n */\r\nexport async function applyPromoCode(\r\n  cartId: string,\r\n  code: string\r\n): Promise<{ success: boolean; error?: string }> {\r\n  try {\r\n    // Backend route: POST /api/orders/v2/public/cart/{uuid}/apply-promo with a\r\n    // `promoCode` body (mirrors apply-gift-card). The old path/body\r\n    // (/orders/{id}/apply-promo + {code}) matched no route, so the cart's\r\n    // DiscountAmount was never set and the buyer was charged full price despite\r\n    // the UI showing a discount.\r\n    const apiResult = await apiPost(\r\n      `${ORDERS_V2_PUBLIC()}/cart/${cartId}/apply-promo`,\r\n      { promoCode: code }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to apply promo code',\r\n      };\r\n    }\r\n\r\n    return { success: true };\r\n  } catch (error) {\r\n    logger.error('Error applying promo code:', error);\r\n    return { success: false, error: 'Network error applying code' };\r\n  }\r\n}\r\n\r\n/**\r\n * Remove a promo code from a cart\r\n *\r\n * @param cartId - The cart UUID\r\n * @returns Success status\r\n */\r\nexport async function removePromoCode(\r\n  cartId: string\r\n): Promise<{ success: boolean; error?: string }> {\r\n  try {\r\n    const apiResult = await apiPost(`/orders/${cartId}/remove-promo`);\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to remove promo code',\r\n      };\r\n    }\r\n\r\n    return { success: true };\r\n  } catch (error) {\r\n    logger.error('Error removing promo code:', error);\r\n    return { success: false, error: 'Network error removing code' };\r\n  }\r\n}\r\n","/**\r\n * Event Performers Transformer\r\n *\r\n * Normalizes the public `GET /events/{id}/performers` response into the\r\n * EventPerformersResponse domain shape consumed by the lineup UI.\r\n *\r\n * Wire->domain boundary: one parseEventPerformers(raw: unknown) entry point.\r\n * The normalization guarantees the two invariants the UI relies on:\r\n *   - `performers` is ALWAYS an array (non-array / missing -> [])\r\n *   - `showPerformers` is ALWAYS a strict boolean (only `=== true` is true)\r\n *\r\n * Byte-identical to the inline mapping previously embedded in\r\n * fetchEventPerformers (src/lib/api/events.ts). The network-failure guard\r\n * (`!data` -> empty response) is a CALLER concern and stays in\r\n * fetchEventPerformers; nullish input here is treated as an empty payload so\r\n * the parser never throws.\r\n */\r\n\r\nimport type { EventPerformersResponse } from '../types.js';\r\n\r\n/**\r\n * Parse a raw performers payload into the normalized EventPerformersResponse.\r\n *\r\n * `performers` is coerced to an array (Array.isArray gate), `showPerformers`\r\n * to a strict boolean (`=== true`) -- matching fetchEventPerformers exactly.\r\n */\r\nexport function parseEventPerformers(raw: unknown): EventPerformersResponse {\r\n  const data = (raw ?? {}) as Partial<EventPerformersResponse>;\r\n  return {\r\n    performers: Array.isArray(data.performers) ? data.performers : [],\r\n    showPerformers: data.showPerformers === true,\r\n  };\r\n}\r\n","/**\r\n * Result — the canonical error channel for API loaders.\r\n *\r\n * The public loaders in this package historically collapsed a failed fetch\r\n * to an empty value (`[]`, `{ performers: [], showPerformers: false }`, or\r\n * `null`), which is indistinguishable from a genuinely empty result. A buyer\r\n * hitting a live event during a transient endpoint blip then sees a dead\r\n * \"No tickets available\" button with no retry; a failed calendar month\r\n * renders dark, so the venue looks like it has nothing on.\r\n *\r\n * `Result<T>` gives loaders a typed error channel so callers can tell\r\n * \"the request failed\" apart from \"there is genuinely nothing here\", and\r\n * offer a retry instead of silently degrading. Loaders expose a `*Result`\r\n * variant returning this; the array/object-returning public functions stay\r\n * as thin fail-open adapters over that variant (single source of truth for\r\n * the fetch + validation logic).\r\n *\r\n * Not to be confused with `ApiResponse<T>` (types.ts) — that is the write-path\r\n * HTTP envelope returned by `apiPost`/`apiGet`/etc. (`{ success, data?, error?,\r\n * statusCode? }`, discriminated on `.success`). `Result<T>` is the read-path\r\n * loader channel, discriminated on `.ok`. They are deliberately separate:\r\n * `ApiResponse` carries transport metadata, `Result` carries only \"loaded vs\r\n * failed\". Check `.ok` on a Result, `.success` on an ApiResponse — never mix.\r\n */\r\n\r\nexport type Result<T> =\r\n  | { ok: true; data: T }\r\n  | { ok: false; error: string; notFound?: boolean };\r\n\r\n/** Wrap a successful value. */\r\nexport function ok<T>(data: T): Result<T> {\r\n  return { ok: true, data };\r\n}\r\n\r\n/**\r\n * Wrap a failure with a short, stable error code (used for i18n/render).\r\n *\r\n * This is a TRANSIENT failure by default (`notFound` is unset) — the request\r\n * couldn't complete (network, timeout, 5xx). Loaders that gate an SSR 404 on a\r\n * Result must treat a plain `err(...)` as retryable (503), not \"gone\" (404), so\r\n * a backend blip never renders a permanent-looking 404 to a buyer or crawler.\r\n */\r\nexport function err(error: string): Result<never> {\r\n  return { ok: false, error };\r\n}\r\n\r\n/**\r\n * Wrap a genuine \"this resource does not exist\" failure (upstream 404).\r\n *\r\n * Distinct from `err(...)`: only this warrants an SSR 404. A transient upstream\r\n * failure must NOT collapse to `errNotFound` — that is exactly the bug this\r\n * channel exists to prevent (a fetch blip becoming a permanent 404).\r\n */\r\nexport function errNotFound(error: string): Result<never> {\r\n  return { ok: false, error, notFound: true };\r\n}\r\n\r\n/** Narrowing guard — true when the result carries data. */\r\nexport function isOk<T>(result: Result<T>): result is { ok: true; data: T } {\r\n  return result.ok;\r\n}\r\n\r\n/**\r\n * Narrowing guard — true when the result is a failure (transient OR not-found).\r\n *\r\n * This package typechecks with `strictNullChecks` off, where the ELSE flow of a\r\n * discriminated union does NOT narrow (`if (r.ok) {…}` narrows the positive\r\n * branch, but the fall-through keeps the full union). Consumers that need the\r\n * failure branch's `error`/`notFound` must narrow POSITIVELY through this guard\r\n * rather than relying on `!r.ok` control flow.\r\n */\r\nexport function isErr<T>(\r\n  result: Result<T>\r\n): result is { ok: false; error: string; notFound?: boolean } {\r\n  return !result.ok;\r\n}\r\n\r\n/**\r\n * Collapse a Result to its data, substituting `fallback` on failure.\r\n *\r\n * This is the fail-open bridge the legacy array/object-returning loaders use\r\n * so existing callers keep their current \"degrade to empty\" behaviour until\r\n * they adopt the Result variant and render an error/retry state.\r\n */\r\nexport function unwrapOr<T>(result: Result<T>, fallback: T): T {\r\n  return result.ok ? result.data : fallback;\r\n}\r\n","import { AppError } from '@getmicdrop/svelte-components';\r\n/**\r\n * Events API\r\n *\r\n * Functions for fetching event data, tickets, and performers\r\n * in the public checkout flow.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nconst logger = createLogger('VC');\r\nimport { getPublicBaseUrl, simpleFetch } from './client.js';\r\nimport { parseEventPerformers } from './transformers/performer.js';\r\nimport { ok, err, errNotFound, unwrapOr, type Result } from './result.js';\r\nimport type {\r\n  Event,\r\n  AvailableTicket,\r\n  EventPerformersResponse,\r\n  SeriesOccurrencesResponse,\r\n  SeriesPageData,\r\n  PublicCollectionData,\r\n  ResolvedEntity,\r\n} from './types.js';\r\n\r\n/**\r\n * In-flight `fetchEventDetails` requests keyed by event ID. Lets\r\n * concurrent callers (Checkout, CartView, EventDetailsView, +page.js\r\n * server load — all of which may run during a single navigation) share\r\n * one HTTP request rather than triggering three.\r\n *\r\n * The entry deletes as soon as the underlying promise settles, so this\r\n * is dedup not cache. For real cache-with-TTL we'd want SWR; that's a\r\n * future milestone.\r\n */\r\nconst _eventDetailsInflight = new Map<string, Promise<Result<Event>>>();\r\n\r\n/**\r\n * Fetch event details, discriminating a real 404 from a transient failure.\r\n *\r\n * The SSR loader (`[id]/[slug]/+page.js`) gates its HTTP status on this: only an\r\n * upstream 404 (`errNotFound`) becomes a page 404. A 5xx, a network error, or a\r\n * timeout is `err(...)` (transient) so the loader can answer 503/retry instead\r\n * of rendering a permanent-looking 404 to a buyer or crawler on a backend blip.\r\n *\r\n * @param eventId - The event ID\r\n * @param customFetch - Optional custom fetch function (for SSR)\r\n * @param password - Optional password for gated events\r\n * @returns `ok(event)`, `errNotFound(...)` for a real 404, or `err(...)` transient\r\n */\r\nexport async function fetchEventDetailsResult(\r\n  eventId: string | number,\r\n  customFetch: typeof fetch = fetch,\r\n  password?: string\r\n): Promise<Result<Event>> {\r\n  // Password-protected events are gated server-side: the detail endpoint returns\r\n  // a stripped teaser (+ passwordRequired:true) until the correct ?password= is\r\n  // supplied. The password varies the dedup key so an unlock re-fetch is never\r\n  // served the cached locked teaser.\r\n  const key = password ? `${eventId}:pw` : String(eventId);\r\n  // Only dedup when using the default fetch — custom-fetch callers\r\n  // (e.g. SvelteKit server loads) bring their own request context.\r\n  if (customFetch === fetch) {\r\n    const inflight = _eventDetailsInflight.get(key);\r\n    if (inflight) return inflight;\r\n  }\r\n\r\n  const run = (async (): Promise<Result<Event>> => {\r\n    try {\r\n      const url = password\r\n        ? `${getPublicBaseUrl()}/events/${eventId}?password=${encodeURIComponent(password)}`\r\n        : `${getPublicBaseUrl()}/events/${eventId}`;\r\n      // @fetch-escape: customFetch injection for SSR context — caller-supplied fetch instance, cannot use simpleFetch\r\n      const response = await customFetch(url);\r\n      if (!response.ok) {\r\n        // 404 = the event genuinely does not exist (removed / bad URL). Anything\r\n        // else (5xx, 429, 408, …) is a transient upstream failure the client\r\n        // already retried in fetchWithRetry — surface it as retryable, not gone.\r\n        if (response.status === 404) {\r\n          return errNotFound('event_not_found');\r\n        }\r\n        logger.error(`Failed to fetch event details: ${response.status}`);\r\n        return err('event_fetch_failed');\r\n      }\r\n      const data = await response.json();\r\n      // A 200 with a falsy/null body means the event is absent (an event is\r\n      // always a non-null object) — treat it as a real 404, matching the old\r\n      // `if (!event) throw error(404)` guard. Without this the loader would\r\n      // deref `null.title` and crash to a generic 500.\r\n      if (!data) {\r\n        return errNotFound('event_not_found');\r\n      }\r\n      return ok(data);\r\n    } catch (error) {\r\n      // Network error / timeout — transient by definition, never a 404.\r\n      logger.error('Error fetching event details:', error);\r\n      return err('event_fetch_failed');\r\n    }\r\n  })();\r\n\r\n  if (customFetch === fetch) {\r\n    _eventDetailsInflight.set(key, run);\r\n    run.finally(() => {\r\n      // Only clear if this same promise is still the inflight one — a\r\n      // later call may have set up a fresh request after the user\r\n      // triggered an explicit refresh.\r\n      if (_eventDetailsInflight.get(key) === run) {\r\n        _eventDetailsInflight.delete(key);\r\n      }\r\n    });\r\n  }\r\n  return run;\r\n}\r\n\r\n/**\r\n * Fetch event details\r\n *\r\n * Gets full event information including venue and ticket data.\r\n *\r\n * Fail-open adapter over {@link fetchEventDetailsResult}: existing in-widget\r\n * callers (Checkout, CartView, EventPage) keep degrading to `null` on any\r\n * failure. SSR loaders that need to answer 404-vs-503 use the Result variant.\r\n *\r\n * @param eventId - The event ID\r\n * @param customFetch - Optional custom fetch function (for SSR)\r\n * @returns Event details or null on error\r\n */\r\nexport async function fetchEventDetails(\r\n  eventId: string | number,\r\n  customFetch: typeof fetch = fetch,\r\n  password?: string\r\n): Promise<Event | null> {\r\n  const result = await fetchEventDetailsResult(eventId, customFetch, password);\r\n  return result.ok ? result.data : null;\r\n}\r\n\r\n/**\r\n * Shared loader skeleton for the public GET read endpoints.\r\n *\r\n * simpleFetch returns `null` on a network/server failure — indistinguishable\r\n * from a genuinely empty result once collapsed to `[]`. This centralises the\r\n * fetch + null-guard + catch so the failure contract lives in ONE place\r\n * instead of eight near-copies: a falsy body becomes `err(errorCode)` (the\r\n * request failed — offer retry); a real payload is mapped and returned as\r\n * `ok(...)` (there is genuinely this much, even if it's an empty list).\r\n *\r\n * `map` normalises the raw payload (e.g. unwrap a `{ events }` wrapper); it\r\n * defaults to identity for endpoints that return the value directly.\r\n */\r\ntype PayloadMap<T> = (_data: unknown) => T;\r\n\r\nasync function loadResult<T>(\r\n  url: string,\r\n  errorCode: string,\r\n  map: PayloadMap<T> = data => data as T\r\n): Promise<Result<T>> {\r\n  try {\r\n    const data = await simpleFetch<unknown>(url);\r\n    if (!data) {\r\n      logger.error(`Failed to load (${errorCode}): network or server error`);\r\n      return err(errorCode);\r\n    }\r\n    return ok(map(data));\r\n  } catch (error) {\r\n    logger.error(`Error loading (${errorCode}):`, error);\r\n    return err(errorCode);\r\n  }\r\n}\r\n\r\n/** Coerce a payload to an array, tolerating a non-array (malformed) body. */\r\nfunction asArray<T>(data: unknown): T[] {\r\n  return Array.isArray(data) ? (data as T[]) : [];\r\n}\r\n\r\n/**\r\n * Fetch available tickets for an event\r\n *\r\n * Returns all ticket types that are currently available for sale.\r\n *\r\n * @param eventId - The event ID\r\n * @returns Array of available tickets\r\n */\r\nexport async function fetchEventTicketsResult(\r\n  eventId: string | number\r\n): Promise<Result<AvailableTicket[]>> {\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/tickets/event/${eventId}`,\r\n    'tickets_fetch_failed',\r\n    asArray<AvailableTicket>\r\n  );\r\n}\r\n\r\nexport async function fetchEventTickets(\r\n  eventId: string | number\r\n): Promise<AvailableTicket[]> {\r\n  // Fail-open adapter — existing callers keep degrading to empty until they\r\n  // adopt fetchEventTicketsResult and render an error/retry state.\r\n  return unwrapOr(await fetchEventTicketsResult(eventId), []);\r\n}\r\n\r\n/**\r\n * Fetch performers for an event\r\n *\r\n * Returns the lineup with pre-resolved avatar URLs.\r\n *\r\n * @param eventId - The event ID\r\n * @returns Performers list and visibility flag\r\n */\r\nexport async function fetchEventPerformersResult(\r\n  eventId: string | number\r\n): Promise<Result<EventPerformersResponse>> {\r\n  if (!eventId) {\r\n    logger.warn('fetchEventPerformers called without eventId');\r\n    return err('performers_missing_event_id');\r\n  }\r\n  // Normalization (performers->array, showPerformers->strict boolean) lives in\r\n  // parseEventPerformers — byte-identical to the inline mapping it replaced.\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/events/${eventId}/performers`,\r\n    'performers_fetch_failed',\r\n    data => parseEventPerformers(data as EventPerformersResponse)\r\n  );\r\n}\r\n\r\nexport async function fetchEventPerformers(\r\n  eventId: string | number\r\n): Promise<EventPerformersResponse> {\r\n  return unwrapOr(await fetchEventPerformersResult(eventId), {\r\n    performers: [],\r\n    showPerformers: false,\r\n  });\r\n}\r\n\r\n/**\r\n * Fetch all venues for an organization\r\n *\r\n * @param orgId - The organization ID\r\n * @returns Array of venues\r\n */\r\nexport async function fetchAllVenuesResult(\r\n  orgId: string | number\r\n): Promise<Result<any[]>> {\r\n  if (!orgId) {\r\n    logger.warn('fetchAllVenues called without orgId');\r\n    return err('venues_missing_org_id');\r\n  }\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/venues/organization/${orgId}`,\r\n    'venues_fetch_failed',\r\n    asArray\r\n  );\r\n}\r\n\r\nexport async function fetchAllVenues(orgId: string | number): Promise<any[]> {\r\n  return unwrapOr(await fetchAllVenuesResult(orgId), []);\r\n}\r\n\r\n/**\r\n * Fetch events for a venue\r\n *\r\n * @param venueId - The venue ID\r\n * @returns Array of events\r\n */\r\nexport async function fetchVenueEventsResult(\r\n  venueId: string | number\r\n): Promise<Result<Event[]>> {\r\n  if (!venueId) {\r\n    logger.warn('fetchVenueEvents called without venueId');\r\n    return err('venue_events_missing_venue_id');\r\n  }\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/events/venue/${venueId}`,\r\n    'venue_events_fetch_failed',\r\n    asArray<Event>\r\n  );\r\n}\r\n\r\nexport async function fetchVenueEvents(\r\n  venueId: string | number\r\n): Promise<Event[]> {\r\n  return unwrapOr(await fetchVenueEventsResult(venueId), []);\r\n}\r\n\r\n/**\r\n * Get events for a specific month\r\n *\r\n * Used for calendar views to efficiently load events.\r\n *\r\n * @param venueId - The venue ID\r\n * @param year - The year (e.g., 2024)\r\n * @param month - The month (1-12)\r\n * @returns Array of events for the month\r\n */\r\n/**\r\n * Unwrap a month payload (bare `Event[]` or `{ events }` wrapper) to an array.\r\n * Shared by the venue and org month loaders so the two stay byte-identical.\r\n */\r\nfunction unwrapMonthEvents(data: { events?: Event[] } | Event[]): Event[] {\r\n  if (Array.isArray(data)) return data;\r\n  return Array.isArray((data as { events?: Event[] }).events)\r\n    ? (data as { events: Event[] }).events\r\n    : [];\r\n}\r\n\r\nexport async function getMonthEventsResult(\r\n  venueId: string | number,\r\n  year: number,\r\n  month: number\r\n): Promise<Result<Event[]>> {\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/events/venue/${venueId}/month/${year}/${month}`,\r\n    'month_events_fetch_failed',\r\n    data => unwrapMonthEvents(data as { events?: Event[] } | Event[])\r\n  );\r\n}\r\n\r\nexport async function getMonthEvents(\r\n  venueId: string | number,\r\n  year: number,\r\n  month: number\r\n): Promise<Event[]> {\r\n  return unwrapOr(await getMonthEventsResult(venueId, year, month), []);\r\n}\r\n\r\n/**\r\n * Get events for an organization for a specific month\r\n *\r\n * @param orgId - The organization ID\r\n * @param year - The year (e.g., 2024)\r\n * @param month - The month (1-12)\r\n * @returns Array of events for the month\r\n */\r\nexport async function getOrgMonthEventsResult(\r\n  orgId: string | number,\r\n  year: number,\r\n  month: number\r\n): Promise<Result<Event[]>> {\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/events/organization/${orgId}/month/${year}/${month}`,\r\n    'org_month_events_fetch_failed',\r\n    data => unwrapMonthEvents(data as { events?: Event[] } | Event[])\r\n  );\r\n}\r\n\r\nexport async function getOrgMonthEvents(\r\n  orgId: string | number,\r\n  year: number,\r\n  month: number\r\n): Promise<Event[]> {\r\n  return unwrapOr(await getOrgMonthEventsResult(orgId, year, month), []);\r\n}\r\n\r\n/**\r\n * Get series occurrences for date selector\r\n *\r\n * Returns all instances of a recurring event series.\r\n *\r\n * @param eventSeriesId - The series ID\r\n * @returns Series occurrences\r\n */\r\nexport async function getSeriesOccurrencesResult(\r\n  eventSeriesId: number\r\n): Promise<Result<SeriesOccurrencesResponse>> {\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/series/${eventSeriesId}/occurrences`,\r\n    'series_occurrences_fetch_failed'\r\n  );\r\n}\r\n\r\nexport async function getSeriesOccurrences(\r\n  eventSeriesId: number\r\n): Promise<SeriesOccurrencesResponse | null> {\r\n  const result = await getSeriesOccurrencesResult(eventSeriesId);\r\n  return result.ok ? result.data : null;\r\n}\r\n\r\n/**\r\n * Fetch series occurrences with CTA state\r\n *\r\n * Returns full series data including availability status.\r\n *\r\n * @param eventSeriesId - The series ID\r\n * @param venueId - The venue ID\r\n * @returns Series occurrences with CTA state\r\n */\r\nexport async function fetchSeriesOccurrencesResult(\r\n  eventSeriesId: number,\r\n  venueId: string | number\r\n): Promise<Result<SeriesOccurrencesResponse>> {\r\n  // Distinct code from getSeriesOccurrencesResult: this is the CTA-state\r\n  // variant (venue-scoped), so telemetry/retry can tell the two apart.\r\n  return loadResult(\r\n    `${getPublicBaseUrl()}/series/${eventSeriesId}/occurrences?venueId=${venueId}`,\r\n    'series_cta_fetch_failed'\r\n  );\r\n}\r\n\r\nexport async function fetchSeriesOccurrences(\r\n  eventSeriesId: number,\r\n  venueId: string | number\r\n): Promise<SeriesOccurrencesResponse | null> {\r\n  const result = await fetchSeriesOccurrencesResult(eventSeriesId, venueId);\r\n  return result.ok ? result.data : null;\r\n}\r\n\r\n/**\r\n * Resolve an entity-agnostic public id to its concrete type + data.\r\n *\r\n * The embed deep-link (`#{id}-{slug}`) carries no type prefix, so a cold\r\n * deep link (the show isn't in the loaded calendar month) needs the backend\r\n * to say whether the id is an event, series, or collection before the widget\r\n * can render the right view. This is the same `/api/v2/public/resolve/{id}`\r\n * endpoint get-micdrop.com's `/e/{slugId}` page resolves server-side; here we\r\n * call it cross-origin from the venue's page (the public API already serves\r\n * the calendar cross-origin, so CORS is in place).\r\n *\r\n * @param id - The entity id (numeric, type-agnostic)\r\n * @param slug - Optional slug hint (lets the backend canonicalize)\r\n * @returns `{ type, id, title, data }` or null on failure\r\n */\r\nexport async function resolvePublicEntity(\r\n  id: string | number,\r\n  slug?: string\r\n): Promise<ResolvedEntity | null> {\r\n  try {\r\n    const qs = slug ? `?slug=${encodeURIComponent(slug)}` : '';\r\n    const data = await simpleFetch<ResolvedEntity>(\r\n      `${getPublicBaseUrl()}/resolve/${encodeURIComponent(String(id))}${qs}`\r\n    );\r\n\r\n    if (!data || !data.type) {\r\n      throw new AppError(\r\n        'Failed to resolve entity',\r\n        'lib/api/events/resolvePublicEntity'\r\n      );\r\n    }\r\n\r\n    return data;\r\n  } catch (error) {\r\n    logger.error('Error resolving public entity:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Fetch series page data\r\n *\r\n * Returns full series information including occurrences, venue, and performers.\r\n *\r\n * @param seriesId - The series ID\r\n * @returns Series page data or null on error\r\n */\r\nexport async function fetchSeriesPage(\r\n  seriesId: string | number\r\n): Promise<SeriesPageData | null> {\r\n  try {\r\n    const data = await simpleFetch<SeriesPageData>(\r\n      `${getPublicBaseUrl()}/series/${seriesId}/page`\r\n    );\r\n\r\n    if (!data) {\r\n      throw new AppError(\r\n        'Failed to fetch series page',\r\n        'lib/api/events/fetchSeriesPage'\r\n      );\r\n    }\r\n\r\n    return data;\r\n  } catch (error) {\r\n    logger.error('Error fetching series page:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Fetch public collection data\r\n *\r\n * Returns collection info including events list.\r\n * For password-protected collections, pass the password to authenticate.\r\n *\r\n * @param collectionId - The collection ID\r\n * @param password - Optional password for protected collections\r\n * @returns Collection data or null on error\r\n */\r\nexport async function fetchPublicCollection(\r\n  collectionId: string | number,\r\n  password?: string\r\n): Promise<PublicCollectionData | null> {\r\n  try {\r\n    // Backend route is GET /api/v2/public/collections/:id (password via ?password=\r\n    // query, read by GetPublicCollection). The previous \"/public\" suffix matched\r\n    // no route and 404'd every public collection fetch.\r\n    const url = password\r\n      ? `${getPublicBaseUrl()}/collections/${collectionId}?password=${encodeURIComponent(password)}`\r\n      : `${getPublicBaseUrl()}/collections/${collectionId}`;\r\n\r\n    const data = await simpleFetch<PublicCollectionData>(url);\r\n\r\n    if (!data) {\r\n      throw new AppError(\r\n        'Failed to fetch collection',\r\n        'lib/api/events/fetchPublicCollection'\r\n      );\r\n    }\r\n\r\n    return data;\r\n  } catch (error) {\r\n    logger.error('Error fetching collection:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Check collection password\r\n *\r\n * Validates password for password-protected collections.\r\n *\r\n * @param collectionId - The collection ID\r\n * @param password - The password to check\r\n * @returns Whether the password is valid\r\n */\r\nexport async function checkCollectionPassword(\r\n  collectionId: string | number,\r\n  password: string\r\n): Promise<boolean> {\r\n  try {\r\n    // Password in the POST body, never the URL (AC-EV-5 — see checkEventPassword).\r\n    // Backend contract: POST /public/collections/:id/check-password { password } -> { valid }.\r\n    const result = await simpleFetch<{ valid: boolean }>(\r\n      `${getPublicBaseUrl()}/collections/${collectionId}/check-password`,\r\n      {\r\n        method: 'POST',\r\n        headers: { 'Content-Type': 'application/json' },\r\n        body: JSON.stringify({ password }),\r\n      }\r\n    );\r\n\r\n    return result?.valid === true;\r\n  } catch (error) {\r\n    logger.error('Error checking collection password:', error);\r\n    return false;\r\n  }\r\n}\r\n\r\n/**\r\n * Check event password\r\n *\r\n * Validates password for password-protected events.\r\n *\r\n * @param eventId - The event ID\r\n * @param password - The password to check\r\n * @returns Whether the password is valid\r\n */\r\nexport async function checkEventPassword(\r\n  eventId: string | number,\r\n  password: string\r\n): Promise<{ valid: boolean }> {\r\n  try {\r\n    // The password rides in the POST body, never the URL. A path/query secret\r\n    // lands in access logs, browser history, and Referer headers (AC-EV-5).\r\n    // Backend contract: POST /public/events/:id/check-password { password } -> { valid }.\r\n    // Guarded by check-password-contract.test.ts — flip both together, deliberately.\r\n    const result = await simpleFetch<{ valid: boolean } | boolean>(\r\n      `${getPublicBaseUrl()}/events/${eventId}/check-password`,\r\n      {\r\n        method: 'POST',\r\n        headers: { 'Content-Type': 'application/json' },\r\n        body: JSON.stringify({ password }),\r\n      }\r\n    );\r\n\r\n    if (typeof result === 'boolean') return { valid: result };\r\n    return { valid: result?.valid === true };\r\n  } catch (error) {\r\n    logger.error('Error checking event password:', error);\r\n    return { valid: false };\r\n  }\r\n}\r\n\r\n/**\r\n * Test network connection\r\n *\r\n * Health check endpoint for connectivity testing.\r\n *\r\n * @param orgId - Optional org ID\r\n * @param venueId - Optional venue ID\r\n * @returns Whether the connection is working\r\n */\r\nexport async function testNetworkConnection(\r\n  orgId?: string | number,\r\n  venueId?: string | number\r\n): Promise<boolean> {\r\n  try {\r\n    // Use a simple endpoint to test connectivity\r\n    const url = venueId\r\n      ? `${getPublicBaseUrl()}/events/venue/${venueId}`\r\n      : orgId\r\n        ? `${getPublicBaseUrl()}/venues/organization/${orgId}`\r\n        : `${getPublicBaseUrl()}/health`;\r\n\r\n    // @fetch-escape: HEAD request for connectivity probe — simpleFetch always parses JSON body; HEAD has no body\r\n    const response = await fetch(url, {\r\n      method: 'HEAD',\r\n    });\r\n\r\n    return response.ok;\r\n  } catch (error) {\r\n    logger.error('Network connection test failed:', error);\r\n    return false;\r\n  }\r\n}\r\n","/**\r\n * Venues API\r\n *\r\n * Functions for fetching venue data including\r\n * service fees and tax configuration.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nconst logger = createLogger('VC');\r\nimport { apiGet } from './client.js';\r\nimport type { Venue } from './types.js';\r\n\r\n/**\r\n * Get venue details (public, no auth required)\r\n *\r\n * Fetches venue information including service fees and taxes\r\n * needed for checkout calculations.\r\n *\r\n * @param venueId - The venue ID\r\n * @returns Venue details or null on error\r\n */\r\nexport async function getVenue(venueId: string | number): Promise<Venue | null> {\r\n  try {\r\n    if (!venueId) {\r\n      logger.warn('getVenue called without venueId');\r\n      return null;\r\n    }\r\n\r\n    const result = await apiGet<Venue>(`/venues/${venueId}`);\r\n    if (!result.success) {\r\n      logger.error(`Failed to fetch venue: ${result.statusCode}`);\r\n      return null;\r\n    }\r\n    return result.data ?? null;\r\n  } catch (error) {\r\n    logger.error('Error fetching venue:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Get venue service fee configuration\r\n *\r\n * Returns just the fee-related fields for checkout calculations.\r\n *\r\n * @param venueId - The venue ID\r\n * @returns Fee configuration or null on error\r\n */\r\nexport async function getVenueFees(\r\n  venueId: string | number\r\n): Promise<{\r\n  serviceFeePercentage: number;\r\n  serviceFeeCents: number;\r\n  taxPercentage: number;\r\n} | null> {\r\n  const venue = await getVenue(venueId);\r\n\r\n  if (!venue) {\r\n    return null;\r\n  }\r\n\r\n  return {\r\n    serviceFeePercentage: venue.serviceFeePercentage ?? 0,\r\n    serviceFeeCents: venue.serviceFeeCents ?? 0,\r\n    taxPercentage: venue.taxPercentage ?? 0,\r\n  };\r\n}\r\n\r\n/**\r\n * Get venue by slug\r\n *\r\n * Fetches venue using its URL-friendly slug.\r\n *\r\n * @param slug - The venue slug\r\n * @returns Venue details or null on error\r\n */\r\nexport async function getVenueBySlug(slug: string): Promise<Venue | null> {\r\n  try {\r\n    if (!slug) {\r\n      logger.warn('getVenueBySlug called without slug');\r\n      return null;\r\n    }\r\n\r\n    const encodedSlug = encodeURIComponent(slug);\r\n    const result = await apiGet<Venue>(`/venues/slug/${encodedSlug}`);\r\n    if (!result.success) {\r\n      logger.error(`Failed to fetch venue by slug: ${result.statusCode}`);\r\n      return null;\r\n    }\r\n    return result.data ?? null;\r\n  } catch (error) {\r\n    logger.error('Error fetching venue by slug:', error);\r\n    return null;\r\n  }\r\n}\r\n","/**\r\n * Gift Card Application Transformer\r\n *\r\n * Normalizes the orders-service `POST /cart/{id}/apply-gift-card` SUCCESS\r\n * payload into the ApplyGiftCardResult shape the Checkout component /\r\n * GiftCardInput consume.\r\n *\r\n * Wire->domain boundary: one parseGiftCardApplication(raw: unknown) entry\r\n * point. The wire field shape (ApplyGiftCardApiResponse) is named ONLY inside\r\n * this module and never escapes. Error paths (429 rate-limit, !success,\r\n * network catch) are CALLER concerns and stay in applyGiftCard -- this parser\r\n * only maps the success body.\r\n *\r\n * UNIT CONTRACT (do NOT \"fix\" this -- VC public endpoints speak cents):\r\n *   Backend ApplyGiftCardResponse (orders-service controllers/cart.go):\r\n *     - appliedAmount   : integer CENTS  (int64)\r\n *     - giftCardBalance : integer CENTS  (int64)\r\n *     - remainingTotal  : DOLLARS        (float64)\r\n *   Domain ApplyGiftCardResult (formatCurrency-ready, DOLLARS):\r\n *     - giftCardAmount  : appliedAmount / 100   (cents -> dollars)\r\n *     - stripeAmount    : remainingTotal        (already dollars, no /100)\r\n *     - giftCardBalance : passed through as-is  (raw CENTS, not displayed via\r\n *                         formatCurrency)\r\n * The cents->dollars conversion lives HERE, exactly where/how the inline\r\n * mapper in applyGiftCard had it -- byte-identical.\r\n */\r\n\r\nimport type { ApplyGiftCardResult } from '../gift-cards.js';\r\n\r\n// -- Wire shape (internal -- never exported) ---------------------------------\r\n// Source of truth: orders-service controllers/cart.go ApplyGiftCardResponse.\r\ninterface ApplyGiftCardApiResponse {\r\n  valid: boolean;\r\n  message?: string;\r\n  giftCardCode?: string;\r\n  giftCardBalance?: number; // cents\r\n  appliedAmount?: number; // cents\r\n  remainingTotal?: number; // dollars\r\n  fullyCoveredByCard?: boolean;\r\n}\r\n\r\n/**\r\n * Parse a successful apply-gift-card backend payload into ApplyGiftCardResult.\r\n *\r\n * Maps the real backend contract to what the Checkout component expects:\r\n *   - appliedAmount (cents) -> giftCardAmount (dollars)\r\n *   - remainingTotal (dollars) -> stripeAmount (dollars, residual to charge)\r\n *   - fullyCoveredByCard -> paymentType 'gift_card_only' | 'split' + requiresStripe\r\n * Byte-identical to the inline success-path mapping previously in applyGiftCard.\r\n */\r\nexport function parseGiftCardApplication(raw: unknown): ApplyGiftCardResult {\r\n  const data = (raw ?? {}) as ApplyGiftCardApiResponse;\r\n\r\n  const giftCardAmountDollars = (data.appliedAmount ?? 0) / 100;\r\n  const residualDollars = data.remainingTotal ?? 0;\r\n  // Full coverage when the card covers everything (no residual to charge).\r\n  const fullyCovered = data.fullyCoveredByCard ?? residualDollars <= 0;\r\n  const requiresStripe = !fullyCovered;\r\n\r\n  return {\r\n    valid: true,\r\n    giftCardCode: data.giftCardCode,\r\n    giftCardAmount: giftCardAmountDollars,\r\n    giftCardBalance: data.giftCardBalance,\r\n    paymentType: fullyCovered ? 'gift_card_only' : 'split',\r\n    stripeAmount: residualDollars,\r\n    orderTotal: giftCardAmountDollars + residualDollars,\r\n    requiresStripe,\r\n  };\r\n}\r\n","import { AppError, asVenueId } from '@getmicdrop/svelte-components';\r\nimport type { VenueId } from '@getmicdrop/svelte-components';\r\n/**\r\n * Gift Card Purchase API Client\r\n * Handles gift card purchase creation, cart application/removal,\r\n * and gift-card-only checkout completion.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nimport { getOrdersV2Url, apiPost, apiDelete } from './client.js';\r\nimport { ok, err, errNotFound, type Result } from './result.js';\r\nimport { parseGiftCardApplication } from './transformers/giftCard.js';\r\nimport { getAttribution } from '../tracking/index.js';\r\nconst logger = createLogger('VC');\r\n\r\nconst API_BASE_URL = 'https://get-micdrop.com';\r\nconst ORDERS_V2_URL = `${API_BASE_URL}/api/orders/v2`;\r\nconst ORDERS_V2_PUBLIC = () => getOrdersV2Url();\r\n\r\n/**\r\n * Request payload for creating a gift card purchase\r\n */\r\nexport interface GiftCardPurchaseRequest {\r\n  // Public boundary — accept plain number too so external TypeScript callers\r\n  // that pass `venueId: 1` keep compiling. Runtime serializes a number either\r\n  // way. Internal call sites pass branded VenueId via asVenueId().\r\n  venueId: number | VenueId;\r\n  amount: number; // In cents (e.g., 5000 = $50.00)\r\n  recipientEmail: string;\r\n  recipientName: string;\r\n  personalMessage?: string;\r\n  purchaserEmail: string;\r\n  purchaserName: string;\r\n  scheduledDeliveryAt?: string | null; // ISO date string or null for immediate\r\n}\r\n\r\n/**\r\n * Response from gift card purchase creation\r\n */\r\nexport interface GiftCardPurchaseResponse {\r\n  giftCardUUID: string;\r\n  clientSecret: string;\r\n  amount: number;\r\n  stripePublishableKey: string;\r\n}\r\n\r\n/**\r\n * Venue information needed for gift card purchase\r\n */\r\nexport interface VenueInfo {\r\n  id: VenueId;\r\n  name: string;\r\n  slug: string;\r\n  stripePublishableKey?: string;\r\n}\r\n\r\n/**\r\n * Create a gift card purchase and get Stripe client secret\r\n * @param req - Gift card purchase request details\r\n * @returns Gift card UUID and Stripe client secret, or null on failure\r\n */\r\nexport async function createGiftCardPurchase(\r\n  req: GiftCardPurchaseRequest\r\n): Promise<GiftCardPurchaseResponse | null> {\r\n  try {\r\n    const apiResult = await apiPost<GiftCardPurchaseResponse>(\r\n      `${ORDERS_V2_URL}/gift-cards`,\r\n      req\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Gift card purchase creation failed:', apiResult.error);\r\n      throw new AppError(\r\n        apiResult.error || 'Failed to create gift card purchase',\r\n        'lib/api/gift-cards/createGiftCardPurchase'\r\n      );\r\n    }\r\n\r\n    logger.debug('Gift card purchase created:', apiResult.data);\r\n    return apiResult.data!;\r\n  } catch (error) {\r\n    logger.error('Gift card purchase creation error:', error);\r\n    return null;\r\n  }\r\n}\r\n\r\n/**\r\n * Result shape consumed by the Checkout component / GiftCardInput.\r\n * Monetary fields here are in DOLLARS (formatCurrency-ready).\r\n */\r\nexport interface ApplyGiftCardResult {\r\n  valid: boolean;\r\n  giftCardCode?: string;\r\n  giftCardAmount?: number; // dollars applied from the gift card\r\n  giftCardBalance?: number; // cents (raw balance, not displayed via formatCurrency)\r\n  paymentType?: string; // 'gift_card_only' (full) | 'split' (partial)\r\n  stripeAmount?: number; // dollars the card must still cover (residual)\r\n  orderTotal?: number; // dollars (gift card + residual)\r\n  requiresStripe?: boolean;\r\n  error?: string;\r\n}\r\n\r\n/**\r\n * Apply a gift card to a cart.\r\n */\r\nexport async function applyGiftCard(\r\n  cartId: string,\r\n  code: string\r\n): Promise<ApplyGiftCardResult> {\r\n  try {\r\n    const apiResult = await apiPost<unknown>(\r\n      `${ORDERS_V2_PUBLIC()}/cart/${cartId}/apply-gift-card`,\r\n      { giftCardCode: code }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      if (apiResult.statusCode === 429) {\r\n        return {\r\n          valid: false,\r\n          error: 'Too many attempts. Please wait a moment and try again.',\r\n        };\r\n      }\r\n      logger.error('Apply gift card failed:', apiResult.error);\r\n      return {\r\n        valid: false,\r\n        error: apiResult.error || 'Invalid gift card code',\r\n      };\r\n    }\r\n\r\n    // Success-path mapping (cents->dollars, fullyCovered/requiresStripe) lives\r\n    // in parseGiftCardApplication — byte-identical to the inline mapper this\r\n    // replaced. The cents->dollars conversion stays in the parser (unit\r\n    // contract documented there). Error/429/network branches stay here.\r\n    return parseGiftCardApplication(apiResult.data);\r\n  } catch (err) {\r\n    logger.error('applyGiftCard error:', err);\r\n    return {\r\n      valid: false,\r\n      error: 'Network error. Please check your connection and try again.',\r\n    };\r\n  }\r\n}\r\n\r\nexport interface RemoveGiftCardResult {\r\n  success: boolean;\r\n  error?: string;\r\n}\r\n\r\n/**\r\n * Remove a gift card from a cart. Pass a `code` to remove a single stacked card;\r\n * omit it to remove all applied gift cards.\r\n */\r\nexport async function removeGiftCard(\r\n  cartId: string,\r\n  code?: string\r\n): Promise<RemoveGiftCardResult> {\r\n  try {\r\n    const apiResult = await apiDelete(\r\n      `${ORDERS_V2_PUBLIC()}/cart/${cartId}/gift-card`,\r\n      code ? { body: JSON.stringify({ giftCardCode: code }) } : undefined\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Remove gift card failed:', apiResult.error);\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to remove gift card',\r\n      };\r\n    }\r\n\r\n    return { success: true };\r\n  } catch (err) {\r\n    logger.error('removeGiftCard error:', err);\r\n    return {\r\n      success: false,\r\n      error: 'Network error. Please check your connection and try again.',\r\n    };\r\n  }\r\n}\r\n\r\nexport interface CompleteGiftCardPaymentInput {\r\n  firstName: string;\r\n  lastName: string;\r\n  email: string;\r\n  phoneNumber?: string | null;\r\n  mailingList?: boolean;\r\n}\r\n\r\nexport interface CompleteGiftCardPaymentResult {\r\n  success: boolean;\r\n  orderId?: string;\r\n  confirmationNumber?: string;\r\n  error?: string;\r\n}\r\n\r\n/**\r\n * Complete a gift-card-only payment (no Stripe required when balance >= total).\r\n */\r\nexport async function completeGiftCardPayment(\r\n  cartId: string,\r\n  customerDetails: CompleteGiftCardPaymentInput\r\n): Promise<CompleteGiftCardPaymentResult> {\r\n  try {\r\n    const apiResult = await apiPost<{\r\n      orderId?: string;\r\n      confirmationNumber?: string;\r\n    }>(`${ORDERS_V2_PUBLIC()}/cart/${cartId}/complete-gift-card-payment`, {\r\n      firstName: customerDetails.firstName,\r\n      lastName: customerDetails.lastName,\r\n      email: customerDetails.email,\r\n      phoneNumber: customerDetails.phoneNumber || null,\r\n      mailingList: customerDetails.mailingList || false,\r\n      // Order attribution (MISSION-TRUTH C2) — gift-card-only orders take this\r\n      // finalize endpoint, so attribution must ride here too; additive.\r\n      attribution: getAttribution(),\r\n    });\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Complete gift card payment failed:', apiResult.error);\r\n      return {\r\n        success: false,\r\n        error: apiResult.error || 'Failed to complete payment',\r\n      };\r\n    }\r\n\r\n    return {\r\n      success: true,\r\n      orderId: apiResult.data?.orderId,\r\n      confirmationNumber: apiResult.data?.confirmationNumber,\r\n    };\r\n  } catch (err) {\r\n    logger.error('completeGiftCardPayment error:', err);\r\n    return {\r\n      success: false,\r\n      error: 'Network error. Please check your connection and try again.',\r\n    };\r\n  }\r\n}\r\n\r\n/**\r\n * Fetch venue information by slug, discriminating a real 404 from a transient\r\n * failure.\r\n *\r\n * The gift-card SSR loader (`v/[venueSlug]/gift-cards/purchase/+page.ts`) gates\r\n * its HTTP status on this: only an upstream 404 (`errNotFound`) becomes a page\r\n * 404. A 5xx, network error, or timeout is `err(...)` (transient) so the loader\r\n * answers 503/retry rather than a permanent-looking 404 on a backend blip.\r\n *\r\n * @param slug - Venue slug\r\n * @param customFetch - Optional custom fetch function (for SSR)\r\n * @returns `ok(venue)`, `errNotFound(...)` for a real 404, or `err(...)` transient\r\n */\r\nexport async function getVenueBySlugResult(\r\n  slug: string,\r\n  customFetch: typeof fetch = fetch\r\n): Promise<Result<VenueInfo>> {\r\n  try {\r\n    // @fetch-escape: customFetch injection for SSR context — cannot use apiGet (caller-supplied fetch instance)\r\n    const response = await customFetch(\r\n      `${API_BASE_URL}/api/v2/public/venues/slug/${slug}`\r\n    );\r\n\r\n    if (!response.ok) {\r\n      // 404 = this venue slug genuinely does not exist. Anything else is a\r\n      // transient upstream failure — surface as retryable, not gone.\r\n      if (response.status === 404) {\r\n        return errNotFound('venue_not_found');\r\n      }\r\n      logger.error(`Failed to fetch venue by slug: ${response.status}`);\r\n      return err('venue_fetch_failed');\r\n    }\r\n\r\n    const venue = await response.json();\r\n    // A 200 with a falsy/null body means the venue is absent — treat it as a\r\n    // real 404 (matches the old behaviour where `venue.id` on null threw and\r\n    // collapsed to a not-found), rather than deref-crashing below.\r\n    if (!venue) {\r\n      return errNotFound('venue_not_found');\r\n    }\r\n    return ok({\r\n      id: asVenueId(venue.id),\r\n      name: venue.name,\r\n      slug: venue.slug,\r\n      stripePublishableKey: venue.stripePublishableKey,\r\n    });\r\n  } catch (error) {\r\n    // Network error / timeout — transient by definition, never a 404.\r\n    logger.error('Error fetching venue by slug:', error);\r\n    return err('venue_fetch_failed');\r\n  }\r\n}\r\n\r\n/**\r\n * Fetch venue information by slug\r\n *\r\n * Fail-open adapter over {@link getVenueBySlugResult}: returns `null` on any\r\n * failure. SSR loaders that need 404-vs-503 use the Result variant.\r\n *\r\n * @param slug - Venue slug\r\n * @returns Venue info or null on failure\r\n */\r\nexport async function getVenueBySlug(\r\n  slug: string,\r\n  customFetch: typeof fetch = fetch\r\n): Promise<VenueInfo | null> {\r\n  const result = await getVenueBySlugResult(slug, customFetch);\r\n  return result.ok ? result.data : null;\r\n}\r\n","/**\r\n * Waitlist API\r\n *\r\n * Endpoints for the sold-out-event waitlist flow.\r\n */\r\n\r\nimport { createLogger } from '@getmicdrop/svelte-components/utils/logger';\r\nimport { apiPost, apiGet } from './client.js';\r\n\r\nconst logger = createLogger('VC');\r\n\r\nexport interface JoinWaitlistResult {\r\n  success: boolean;\r\n  // No position — opaque to the customer (decision #2/#20).\r\n  updated?: boolean;\r\n  error?: string;\r\n}\r\n\r\nconst WAITLIST_ERROR_MESSAGES: Record<string, string> = {\r\n  waitlist_not_enabled: 'Waitlist is not available for this event',\r\n  event_not_found: 'Event not found',\r\n  invalid_phone: 'Please enter a valid phone number',\r\n  already_purchased: 'You have already purchased tickets for this event',\r\n  phone_already_registered: 'This phone number is already on the waitlist',\r\n};\r\n\r\n/**\r\n * Join the waitlist for a sold-out event.\r\n */\r\nexport async function joinWaitlist(\r\n  eventId: string | number,\r\n  email: string,\r\n  phone: string | null = null,\r\n  smsOptIn = false\r\n): Promise<JoinWaitlistResult> {\r\n  try {\r\n    const body: Record<string, unknown> = { email };\r\n    if (phone && smsOptIn) {\r\n      body.phone = phone;\r\n      body.smsOptIn = true;\r\n    }\r\n\r\n    const apiResult = await apiPost<{ updated?: boolean }>(\r\n      `/events/${eventId}/waitlist`,\r\n      body\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      logger.error('Join waitlist failed:', apiResult.error);\r\n      return {\r\n        success: false,\r\n        error:\r\n          WAITLIST_ERROR_MESSAGES[apiResult.error ?? ''] ||\r\n          'Failed to join waitlist. Please try again.',\r\n      };\r\n    }\r\n\r\n    return {\r\n      success: true,\r\n      updated: apiResult.data?.updated,\r\n    };\r\n  } catch (err) {\r\n    logger.error('joinWaitlist error:', err);\r\n    return {\r\n      success: false,\r\n      error: 'Network error. Please check your connection and try again.',\r\n    };\r\n  }\r\n}\r\n\r\nexport interface ValidateWaitlistTokenResult {\r\n  valid: boolean;\r\n  eventId: number;\r\n  /**\r\n   * Present only when `valid` is false. One of the server's failure enums:\r\n   * invalid_token | token_expired | token_used | email_mismatch |\r\n   * inventory_exhausted. Callers map it to friendly copy.\r\n   */\r\n  errorCode?: string;\r\n}\r\n\r\n/**\r\n * Validate a tokenized waitlist unlock link (decisions #3/#22/#36).\r\n *\r\n * A waitlister receives an email link carrying an opaque token bound to their\r\n * email. Presenting a valid (token, email) pair unlocks the normal Buy Tickets\r\n * flow on an otherwise-gated sold-out event, routing freed inventory to the\r\n * notified buyer. Failures are surfaced (not thrown) so the page can show a\r\n * non-blocking notice while keeping the event in its gated waitlist state.\r\n */\r\nexport async function validateWaitlistToken(\r\n  token: string,\r\n  email: string\r\n): Promise<ValidateWaitlistTokenResult> {\r\n  try {\r\n    const apiResult = await apiPost<{ eventId?: number }>(\r\n      `/checkout/validate-token/${token}`,\r\n      { email }\r\n    );\r\n\r\n    if (!apiResult.success) {\r\n      return {\r\n        valid: false,\r\n        eventId: 0,\r\n        errorCode: apiResult.error,\r\n      };\r\n    }\r\n\r\n    return {\r\n      valid: true,\r\n      eventId: apiResult.data?.eventId ?? 0,\r\n    };\r\n  } catch (err) {\r\n    logger.error('validateWaitlistToken error:', err);\r\n    return { valid: false, eventId: 0, errorCode: 'invalid_token' };\r\n  }\r\n}\r\n\r\nexport interface WaitlistStatusResult {\r\n  waitlistEnabled: boolean;\r\n  soldOut: boolean;\r\n  /**\r\n   * When gated, the public event page should present \"Sold Out — join the\r\n   * waitlist\" to non-members even if tickets are technically available, and only\r\n   * a valid tokenized link unlocks checkout (reconciled decision #3).\r\n   */\r\n  gated: boolean;\r\n}\r\n\r\n/**\r\n * Fetch an event's waitlist gating status. Returns a non-gated default if the\r\n * request fails so the page degrades to normal behavior.\r\n */\r\nexport async function getWaitlistStatus(\r\n  eventId: string | number\r\n): Promise<WaitlistStatusResult> {\r\n  const fallback: WaitlistStatusResult = {\r\n    waitlistEnabled: false,\r\n    soldOut: false,\r\n    gated: false,\r\n  };\r\n  try {\r\n    const apiResult = await apiGet<{ waitlistEnabled: boolean; soldOut: boolean; gated: boolean }>(\r\n      `/events/${eventId}/waitlist/status`\r\n    );\r\n    if (!apiResult.success) return fallback;\r\n    return {\r\n      waitlistEnabled: !!apiResult.data?.waitlistEnabled,\r\n      soldOut: !!apiResult.data?.soldOut,\r\n      gated: !!apiResult.data?.gated,\r\n    };\r\n  } catch (err) {\r\n    logger.error('getWaitlistStatus error:', err);\r\n    return fallback;\r\n  }\r\n}\r\n","/**\r\n * CTA state computation.\r\n *\r\n * Pure function (no I/O) — derives the buy-button state from an event and\r\n * its ticket list. Lives in `api/` because it is the canonical, single\r\n * source of truth that replaces the duplicate implementations previously\r\n * scattered across utils/api.js, core/api-client.js, and a few components.\r\n */\r\n\r\n// Import from the specific subpath (not the bare entry) so the api/\r\n// bundle doesn't pull in the entire SC component graph (Accordion etc.)\r\n// and break `npm run build:api`. `formatLocal` is the sanctioned browser-local\r\n// (no-timezone) Intl label home — these \"On sale …\" countdown labels render in\r\n// the viewer's own clock, so no venue timezone applies. The datetime subpath is\r\n// leaf/component-free; only `formatLocal` (→ Intl) is pulled, no date-fns.\r\nimport { formatLocal } from '@getmicdrop/svelte-components/datetime';\r\n// Hidden-ticket predicate from the `/transforms` leaf subpath (no component\r\n// graph, so `npm run build:api` stays clean). SC's copy was pinned FROM this\r\n// body (dedup #392) and additionally honours the backend-resolved\r\n// `effectiveSales*` window for relative-offset tickets (#388). Imported (not\r\n// just re-exported) so it stays in local scope for `computeCtaState` below.\r\nimport { isHiddenTicketPurchasable } from '@getmicdrop/svelte-components/transforms';\r\n\r\nexport interface CtaStateOptions {\r\n  cancelled?: boolean;\r\n  isRegistration?: boolean;\r\n  waitlistEnabled?: boolean;\r\n}\r\n\r\nexport interface CtaState {\r\n  text: string;\r\n  disabled: boolean;\r\n  reason:\r\n    | 'cancelled'\r\n    | 'event_past'\r\n    | 'no_tickets'\r\n    | 'available'\r\n    | 'coming_soon'\r\n    | 'sold_out_waitlist'\r\n    | 'sold_out'\r\n    | 'sales_ended'\r\n    | 'hidden_only';\r\n}\r\n\r\ninterface CtaEvent {\r\n  startDateTime?: string | null;\r\n  endDateTime?: string | null;\r\n  hasPurchasableHiddenTickets?: boolean;\r\n}\r\n\r\ninterface CtaTicket {\r\n  salesChannel?: number;\r\n  salesBegin?: string | null;\r\n  salesStart?: string | null;\r\n  saleBegin?: string | null;\r\n  onSaleStart?: string | null;\r\n  salesEnd?: string | null;\r\n  saleEnd?: string | null;\r\n  onSaleEnd?: string | null;\r\n  remainingCapacity?: number | null;\r\n  quantityRemaining?: number | null;\r\n  quantity?: number | null;\r\n  soldOut?: boolean;\r\n  isHidden?: boolean;\r\n  visibility?: number;\r\n}\r\n\r\n// A hidden ticket (visibility>=2 or isHidden) that's still on sale drives the\r\n// \"Sales ended\" / \"Sold out\" / \"No tickets\" → \"Get tickets\" override. The user\r\n// just needs the promo code to see it. Re-exported from the SC canonical so\r\n// existing consumers (cta.test.ts, computeCtaState) keep their import path while\r\n// the single-source body lives in SC (dedup #392).\r\nexport { isHiddenTicketPurchasable };\r\n\r\nexport function computeCtaState(\r\n  event: CtaEvent,\r\n  tickets: CtaTicket[] | undefined,\r\n  options: CtaStateOptions = {}\r\n): CtaState {\r\n  const {\r\n    cancelled = false,\r\n    isRegistration = false,\r\n    waitlistEnabled = false,\r\n  } = options;\r\n  const now = new Date();  // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n\r\n  if (cancelled)\r\n    return { text: 'Cancelled', disabled: true, reason: 'cancelled' };\r\n\r\n  const eventEnd = event.endDateTime || event.startDateTime;\r\n  // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n  if (eventEnd && new Date(eventEnd) < now) {\r\n    return { text: 'Sales ended', disabled: true, reason: 'event_past' };\r\n  }\r\n\r\n  const hiddenAvailable =\r\n    event?.hasPurchasableHiddenTickets === true ||\r\n    (Array.isArray(tickets) && tickets.some(isHiddenTicketPurchasable));\r\n\r\n  const publicTickets = (tickets || []).filter(\r\n    t =>\r\n      t.salesChannel !== 2 &&\r\n      !t.isHidden &&\r\n      !(typeof t.visibility === 'number' && t.visibility >= 2)\r\n  );\r\n  if (publicTickets.length === 0) {\r\n    if (hiddenAvailable) {\r\n      return {\r\n        text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n        disabled: false,\r\n        reason: 'hidden_only',\r\n      };\r\n    }\r\n    return {\r\n      text: 'No tickets available',\r\n      disabled: true,\r\n      reason: 'no_tickets',\r\n    };\r\n  }\r\n\r\n  let hasPurchasable = false;\r\n  let allSoldOut = true;\r\n  let allComingSoon = true;\r\n  let earliestSalesStart: Date | null = null;\r\n\r\n  for (const ticket of publicTickets) {\r\n    const salesBegin =\r\n      ticket.salesBegin ||\r\n      ticket.salesStart ||\r\n      ticket.saleBegin ||\r\n      ticket.onSaleStart;\r\n    const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n    const remaining =\r\n      ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n    const isSoldOut =\r\n      ticket.soldOut ||\r\n      (remaining !== null && remaining !== undefined && remaining <= 0);\r\n\r\n    const isScheduled = salesBegin ? new Date(salesBegin) > now : false;  // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n    const hasSalesEnded = salesEnd ? new Date(salesEnd) < now : false;  // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n    const isPurchasable = !isSoldOut && !isScheduled && !hasSalesEnded;\r\n\r\n    if (isPurchasable) hasPurchasable = true;\r\n    if (!isSoldOut) allSoldOut = false;\r\n    if (!isScheduled) allComingSoon = false;\r\n\r\n    if (isScheduled && salesBegin && !isSoldOut && !hasSalesEnded) {\r\n      const startDate = new Date(salesBegin);  // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n      if (!earliestSalesStart || startDate < earliestSalesStart) {\r\n        earliestSalesStart = startDate;\r\n      }\r\n    }\r\n  }\r\n\r\n  if (hasPurchasable) {\r\n    return {\r\n      text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n      disabled: false,\r\n      reason: 'available',\r\n    };\r\n  }\r\n\r\n  if (allComingSoon && earliestSalesStart) {\r\n    if (hiddenAvailable) {\r\n      return {\r\n        text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n        disabled: false,\r\n        reason: 'hidden_only',\r\n      };\r\n    }\r\n    const diffMs = earliestSalesStart.getTime() - now.getTime();\r\n    const diffHours = diffMs / (1000 * 60 * 60);\r\n    const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n    // Viewer-local time label (\"8:00 PM\") — the shape shared by the <24h branch\r\n    // and the >7d composite. Matches the deprecated `formatTime(d,{hour12:true})`\r\n    // defaults-merge exactly.\r\n    const timeLabel = (d: Date) =>\r\n      formatLocal(\r\n        d,\r\n        { hour: 'numeric', minute: '2-digit', hour12: true },\r\n        'en-US'\r\n      );\r\n    let dateText: string;\r\n    if (diffHours < 24) {\r\n      dateText = timeLabel(earliestSalesStart);\r\n    } else if (diffDays <= 7) {\r\n      dateText = formatLocal(\r\n        earliestSalesStart,\r\n        { weekday: 'short', hour: 'numeric', minute: '2-digit', hour12: true },\r\n        'en-US'\r\n      );\r\n    } else {\r\n      const d = formatLocal(\r\n        earliestSalesStart,\r\n        { month: 'short', day: 'numeric' },\r\n        'en-US'\r\n      );\r\n      dateText = `${d} ${timeLabel(earliestSalesStart)}`;\r\n    }\r\n    return {\r\n      text: `On sale ${dateText}`,\r\n      disabled: true,\r\n      reason: 'coming_soon',\r\n    };\r\n  }\r\n\r\n  if (allSoldOut) {\r\n    if (hiddenAvailable) {\r\n      return {\r\n        text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n        disabled: false,\r\n        reason: 'hidden_only',\r\n      };\r\n    }\r\n    if (waitlistEnabled) {\r\n      return {\r\n        text: 'Join Waitlist',\r\n        disabled: false,\r\n        reason: 'sold_out_waitlist',\r\n      };\r\n    }\r\n    return { text: 'Sold out', disabled: true, reason: 'sold_out' };\r\n  }\r\n\r\n  if (hiddenAvailable) {\r\n    return {\r\n      text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n      disabled: false,\r\n      reason: 'hidden_only',\r\n    };\r\n  }\r\n\r\n  return { text: 'Sales ended', disabled: true, reason: 'sales_ended' };\r\n}\r\n","// @currency-escape: widget-intentional.\r\nimport { asUSD, formatCurrency } from '@getmicdrop/svelte-components';\r\n/**\r\n * Order Transformer\r\n *\r\n * Normalizes API order responses to a consistent format.\r\n * Handles variations in field names between different API versions.\r\n *\r\n * Wire->domain boundary: one parseOrder(raw: unknown) entry point.\r\n * The wire field shapes (ApiOrder / ApiTicket) are named only inside this\r\n * module and never escape it.\r\n *\r\n * IMPLEMENTATION NOTE -- why no Zod schema here:\r\n * The old mapper used `||` for id and ALL money fields (totalAmount, serviceFeesAmount,\r\n * taxAmount, discount -- 0 falls through to next variant). The old mapper did NOT use\r\n * `??` for money; that was a bug in the first Zod-based rewrite. Replicated verbatim\r\n * for byte-identical behavior. Throw behavior is identical to the old mapper: null/\r\n * null/undefined input or a non-array (the latter throws on .map) tickets field throws exactly as the old code did.\r\n * Callers always pass real wire objects.\r\n */\r\n\r\nimport type { Order, PurchasedTicket } from '../types.js';\r\n\r\n// ── Wire shapes (internal -- never exported) ─────────────────────────────\r\ninterface ApiTicket {\r\n  uuid?: string;\r\n  id?: number;\r\n  ID?: number;\r\n  ticketNumber?: string;\r\n  ticket_number?: string;\r\n  orderId?: string | number;\r\n  order_id?: string | number;\r\n  attendeeFirstName?: string;\r\n  attendee_first_name?: string;\r\n  firstName?: string;\r\n  attendeeLastName?: string;\r\n  attendee_last_name?: string;\r\n  lastName?: string;\r\n  attendeeEmail?: string;\r\n  attendee_email?: string;\r\n  email?: string;\r\n  ticketName?: string;\r\n  ticket_name?: string;\r\n  name?: string;\r\n  ticketTypeId?: number;\r\n  ticket_type_id?: number;\r\n  purchasePrice?: number;\r\n  purchase_price?: number;\r\n  price?: number;\r\n  status?: string;\r\n  checkedIn?: boolean;\r\n  checked_in?: boolean;\r\n  checkedInAt?: string;\r\n  checked_in_at?: string;\r\n}\r\n\r\ninterface ApiOrder {\r\n  uuid?: string;\r\n  id?: number;\r\n  ID?: number;\r\n  customerEmail?: string;\r\n  email?: string;\r\n  customer_email?: string;\r\n  customerFirstName?: string;\r\n  firstName?: string;\r\n  first_name?: string;\r\n  customerLastName?: string;\r\n  lastName?: string;\r\n  last_name?: string;\r\n  status?: string;\r\n  totalAmount?: number;\r\n  total?: number;\r\n  total_amount?: number;\r\n  subtotal?: number;\r\n  serviceFeesAmount?: number;\r\n  serviceFee?: number;\r\n  service_fee?: number;\r\n  service_fees_amount?: number;\r\n  taxAmount?: number;\r\n  tax?: number;\r\n  tax_amount?: number;\r\n  discount?: number;\r\n  paymentIntentId?: string;\r\n  payment_intent_id?: string;\r\n  paymentMethod?: string;\r\n  payment_method?: string;\r\n  purchasedTickets?: any[];\r\n  tickets?: any[];\r\n  purchased_tickets?: any[];\r\n  createdAt?: string;\r\n  created_at?: string;\r\n  updatedAt?: string;\r\n  updated_at?: string;\r\n}\r\n\r\n/**\r\n * Parse a raw purchased-ticket payload into the normalized PurchasedTicket domain shape.\r\n *\r\n * Wire shape (ApiTicket) is contained inside this module. Uses `||` chains matching\r\n * the old transformer exactly -- byte-identical to previous behavior. Throw behavior\r\n * preserved from old mapper: null/undefined input (property access on a nullish value) throws as the old code did.\r\n */\r\nexport function parsePurchasedTicket(raw: unknown): PurchasedTicket {\r\n  const apiTicket = raw as ApiTicket;\r\n  return {\r\n    uuid: apiTicket.uuid || String(apiTicket.id || apiTicket.ID || ''),\r\n    id: apiTicket.id || apiTicket.ID,\r\n    ticketNumber: apiTicket.ticketNumber || apiTicket.ticket_number,\r\n    orderId: apiTicket.orderId || apiTicket.order_id,\r\n    attendeeFirstName:\r\n      apiTicket.attendeeFirstName ||\r\n      apiTicket.attendee_first_name ||\r\n      apiTicket.firstName,\r\n    attendeeLastName:\r\n      apiTicket.attendeeLastName ||\r\n      apiTicket.attendee_last_name ||\r\n      apiTicket.lastName,\r\n    attendeeEmail:\r\n      apiTicket.attendeeEmail || apiTicket.attendee_email || apiTicket.email,\r\n    ticketName:\r\n      apiTicket.ticketName || apiTicket.ticket_name || apiTicket.name || '',\r\n    ticketTypeId: apiTicket.ticketTypeId || apiTicket.ticket_type_id,\r\n    purchasePrice:\r\n      apiTicket.purchasePrice ||\r\n      apiTicket.purchase_price ||\r\n      apiTicket.price ||\r\n      0,\r\n    status: apiTicket.status,\r\n    checkedIn: apiTicket.checkedIn || apiTicket.checked_in,\r\n    checkedInAt: apiTicket.checkedInAt || apiTicket.checked_in_at,\r\n  };\r\n}\r\n\r\n/**\r\n * Parse a raw order payload into the normalized Order domain shape.\r\n *\r\n * Wire shape (ApiOrder) is contained inside this module and never escapes it.\r\n * Uses `||` chains matching the old transformer exactly (all money fields use `||`,\r\n * not `??` -- 0-valued amounts fall through to next variant, same as old) --\r\n * byte-identical to previous behavior. Throw behavior preserved from old mapper:\r\n * null/undefined input (property access on a nullish value) or a non-array tickets field throws as the old code did.\r\n */\r\nexport function parseOrder(raw: unknown): Order {\r\n  const apiOrder = raw as ApiOrder;\r\n\r\n  // Extract tickets array from various possible field names\r\n  const rawTickets =\r\n    apiOrder.purchasedTickets ||\r\n    apiOrder.tickets ||\r\n    apiOrder.purchased_tickets ||\r\n    [];\r\n\r\n  return {\r\n    uuid: apiOrder.uuid || String(apiOrder.id || apiOrder.ID || ''),\r\n    id: apiOrder.id || apiOrder.ID,\r\n    customerEmail:\r\n      apiOrder.customerEmail || apiOrder.email || apiOrder.customer_email || '',\r\n    customerFirstName:\r\n      apiOrder.customerFirstName || apiOrder.firstName || apiOrder.first_name,\r\n    customerLastName:\r\n      apiOrder.customerLastName || apiOrder.lastName || apiOrder.last_name,\r\n    status: apiOrder.status || 'unknown',\r\n    totalAmount:\r\n      apiOrder.totalAmount || apiOrder.total || apiOrder.total_amount || 0,\r\n    subtotal: apiOrder.subtotal,\r\n    serviceFeesAmount:\r\n      apiOrder.serviceFeesAmount ||\r\n      apiOrder.serviceFee ||\r\n      apiOrder.service_fee ||\r\n      apiOrder.service_fees_amount ||\r\n      0,\r\n    taxAmount: apiOrder.taxAmount || apiOrder.tax || apiOrder.tax_amount || 0,\r\n    discount: apiOrder.discount || 0,\r\n    paymentIntentId: apiOrder.paymentIntentId || apiOrder.payment_intent_id,\r\n    paymentMethod: apiOrder.paymentMethod || apiOrder.payment_method,\r\n    purchasedTickets: rawTickets.map(parsePurchasedTicket),\r\n    createdAt: apiOrder.createdAt || apiOrder.created_at,\r\n    updatedAt: apiOrder.updatedAt || apiOrder.updated_at,\r\n  };\r\n}\r\n\r\n/**\r\n * Back-compat alias -- existing call sites using transformTicket continue\r\n * to work unchanged.\r\n */\r\nexport const transformTicket = parsePurchasedTicket;\r\n\r\n/**\r\n * Back-compat alias -- existing call sites using transformOrder(apiOrder)\r\n * continue to work unchanged.\r\n */\r\nexport const transformOrder = parseOrder;\r\n\r\n/**\r\n * Transform order for display on success page.\r\n *\r\n * Returns a simplified object with display-ready values.\r\n */\r\nexport function transformOrderForDisplay(raw: unknown): {\r\n  orderId: string;\r\n  displayOrderId: string;\r\n  email: string;\r\n  customerName: string;\r\n  total: number;\r\n  formattedTotal: string;\r\n  ticketCount: number;\r\n  status: string;\r\n} {\r\n  const order = parseOrder(raw);\r\n  const displayId = order.uuid.split('-')[0] || order.uuid;\r\n  // Coerce before the finite check -- totalAmount is wire data typed as\r\n  // `number` but not schema-validated (see the no-Zod note above), and the\r\n  // old bare `as USD` cast tolerated a numeric-string wire value via the\r\n  // `/` operator's implicit coercion. `Number()` preserves that tolerance;\r\n  // a plain `Number.isFinite(order.totalAmount)` would not.\r\n  const rawTotal = Number(order.totalAmount);\r\n\r\n  return {\r\n    orderId: order.uuid,\r\n    displayOrderId: displayId,\r\n    email: order.customerEmail,\r\n    customerName: [order.customerFirstName, order.customerLastName]\r\n      .filter(Boolean)\r\n      .join(' '),\r\n    total: order.totalAmount,\r\n    formattedTotal: `${formatCurrency(asUSD(Number.isFinite(rawTotal) ? rawTotal / 100 : 0))}`,\r\n    ticketCount: order.purchasedTickets.length,\r\n    status: order.status,\r\n  };\r\n}\r\n","/**\r\n * Event Transformer\r\n *\r\n * Normalizes API event responses to a consistent format.\r\n * Handles image URL resolution and CTA state calculation.\r\n *\r\n * Wire->domain boundary: one parse<Entity>(raw: unknown) per entity.\r\n * The wire field shape (ApiEvent / ApiTicket interface) is named only inside\r\n * this module and never escapes it. Above the boundary only Event / AvailableTicket.\r\n *\r\n * IMPLEMENTATION NOTE — why no Zod schema here:\r\n * The old mappers used `||` (falsy fallthrough) for every primitive field, so\r\n * {venueId:0, venue_id:7} -> 7, {isHidden:false, is_hidden:true} -> true, etc.\r\n * Zod z.number()/z.boolean() would throw on wrong primitive types; firstDefined\r\n * (??) would silently mis-select 0/false values. This implementation replicates\r\n * the old `||` chains verbatim, wrapped in a typed parse<Entity>(raw: unknown)\r\n * boundary. Throw behavior is identical to the old mapper: null/undefined input (property access on a nullish value)\r\n * or a non-array where .map is called throws exactly as the old code did. Callers\r\n * always pass real wire objects.\r\n */\r\n\r\nimport { resolveImageUrl } from '@getmicdrop/svelte-components';\r\nimport type { Event, AvailableTicket } from '../types.js';\r\n\r\n// ── Wire shape (internal — never exported) ───────────────────────────────\r\ninterface ApiTicket {\r\n  id?: number;\r\n  ID?: number;\r\n  name?: string;\r\n  ticketName?: string;\r\n  description?: string;\r\n  price?: number;\r\n  quantity?: number;\r\n  totalQuantity?: number;\r\n  quantitySold?: number;\r\n  quantity_sold?: number;\r\n  quantityAvailable?: number;\r\n  quantity_available?: number;\r\n  minPerOrder?: number;\r\n  min_per_order?: number;\r\n  maxPerOrder?: number;\r\n  max_per_order?: number;\r\n  saleStartDate?: string;\r\n  sale_start_date?: string;\r\n  saleEndDate?: string;\r\n  sale_end_date?: string;\r\n  isHidden?: boolean;\r\n  is_hidden?: boolean;\r\n  revealWithPromoCode?: boolean;\r\n  reveal_with_promo_code?: boolean;\r\n  ticketType?: number;\r\n  ticket_type?: number;\r\n  sectionId?: number;\r\n  section_id?: number;\r\n  sortOrder?: number;\r\n  sort_order?: number;\r\n}\r\n\r\ninterface ApiEvent {\r\n  eventID?: number;\r\n  id?: number;\r\n  ID?: number;\r\n  name?: string;\r\n  title?: string;\r\n  slug?: string;\r\n  description?: string;\r\n  date?: string;\r\n  startDateTime?: string;\r\n  start_date_time?: string;\r\n  endDateTime?: string;\r\n  end_date_time?: string;\r\n  doorsOpenTime?: string;\r\n  doors_open_time?: string;\r\n  timezone?: string;\r\n  time_zone?: string;\r\n  venueId?: number;\r\n  venue_id?: number;\r\n  venueName?: string;\r\n  venue_name?: string;\r\n  venueAddress?: string;\r\n  venue_address?: string;\r\n  location?: string;\r\n  imageUrl?: string;\r\n  imageURL?: string;\r\n  image_url?: string;\r\n  image?: string;\r\n  status?: string;\r\n  isPublished?: boolean;\r\n  is_published?: boolean;\r\n  isCancelled?: boolean;\r\n  is_cancelled?: boolean;\r\n  availableTickets?: any[];\r\n  available_tickets?: any[];\r\n  tickets?: any[];\r\n  ticketsAvailable?: number;\r\n  tickets_available?: number;\r\n  ticketsSold?: number;\r\n  tickets_sold?: number;\r\n  minPrice?: number;\r\n  min_price?: number;\r\n  maxPrice?: number;\r\n  max_price?: number;\r\n  ctaText?: string;\r\n  cta_text?: string;\r\n  ctaState?: string;\r\n  cta_state?: string;\r\n  showPerformers?: boolean;\r\n  show_performers?: boolean;\r\n  eventSeriesId?: number;\r\n  event_series_id?: number;\r\n  seriesInstanceNumber?: number;\r\n  series_instance_number?: number;\r\n  // ── Passthrough seam fields (events convergence) ──────────────────────\r\n  // Carried verbatim onto the domain Event so the view-shape projections\r\n  // (utils/event-transform.js DETAIL/BROWSE, pcf/transform.ts EventData) can\r\n  // compose parseEvent instead of reading the wire directly. See the\r\n  // composition note above parseEvent.\r\n  timeZone?: string; // PascalCase variant some admin payloads carry\r\n  eventSummary?: string;\r\n  password?: string;\r\n  hasPassword?: boolean;\r\n  disclaimer?: string;\r\n  ticketType?: number; // event-level ticketing type (1 = registration)\r\n  eventTicketingType?: number;\r\n  ageRestriction?: number;\r\n  displayAgeRestriction?: boolean;\r\n  displayStartTime?: boolean;\r\n  displayEndTime?: boolean;\r\n  displayDoorsTime?: boolean;\r\n  collectionId?: number;\r\n  collection_id?: number;\r\n  ticketsRemaining?: number; // backend-supplied scarcity (org-month endpoint)\r\n  ticketsTotal?: number;\r\n  hasHiddenTickets?: boolean;\r\n  stage?: { name?: string } | null;\r\n  stageName?: string;\r\n  // Widget-filter dimensions carried by the public month feeds (venue +\r\n  // organization). publicPerformers is the backend's redacted summary\r\n  // (id/displayName/image) — ids are roster-performer ids, the same id-space\r\n  // the widget builder's performer filter saves.\r\n  stageId?: number;\r\n  eventCategoryTypes?: number[] | null;\r\n  publicPerformers?: Array<{\r\n    id?: number;\r\n    displayName?: string;\r\n    image?: string;\r\n  }> | null;\r\n  collectionIds?: number[] | null;\r\n  venue?: Record<string, any>;\r\n  performers?: Record<string, any>[];\r\n  faqs?: Record<string, any>[];\r\n  showtimes?: Record<string, any>[];\r\n  purchasedTickets?: Record<string, any>[];\r\n}\r\n\r\n/**\r\n * Get CDN image URL.\r\n *\r\n * Delegates the host-join to SC's canonical `resolveImageUrl` (one path-join,\r\n * one host constant). `{ cdn: true }` picks the Cloudflare-fronted CDN base\r\n * (`moxy.sfo3.cdn`), the correct, edge-cached host for public buyer surfaces.\r\n *\r\n * This replaced VC's local `micdrop-images.sfo3` bucket, which 404s for real\r\n * event/venue keys (CDN census 2026-07-05, ledger vc-getcdnimageurl-wrong-\r\n * bucket-404). SC additionally passes `data:`/`blob:` URLs through untouched\r\n * and normalizes a missing leading slash — a strict superset of the old body.\r\n */\r\nexport function getCDNImageUrl(path: string | undefined): string {\r\n  return resolveImageUrl(path, { cdn: true });\r\n}\r\n\r\n/**\r\n * Extract image URL from event with fallbacks.\r\n *\r\n * DIVERGENCE (no-shadowed-helper rename-keep): the HOST-JOIN is now the SC\r\n * canonical (via `getCDNImageUrl` above); only the FIELD PRECEDENCE stays local\r\n * and deliberately differs -- this transformer reads\r\n * `imageUrl -> imageURL -> image_url -> image` (incl. the camelCase `imageURL`,\r\n * asserted by event.test.ts), whereas SC reads\r\n * `image -> coverImage -> imageUrl -> image_url`. The VC chain is what this\r\n * wire boundary trusts; changing it would repoint which field wins for the same\r\n * event, so it is preserved. Declared under a non-shadowing name and\r\n * re-exported below as `getEventImageUrl` so call sites keep their existing\r\n * import -- satisfies `micdrop/no-shadowed-helper` without suppression.\r\n */\r\nfunction getEventImageUrlByFieldPrecedence(apiEvent: ApiEvent): string {\r\n  const rawUrl =\r\n    apiEvent.imageUrl ||\r\n    apiEvent.imageURL ||\r\n    apiEvent.image_url ||\r\n    apiEvent.image ||\r\n    '';\r\n\r\n  return getCDNImageUrl(rawUrl);\r\n}\r\n\r\nexport { getEventImageUrlByFieldPrecedence as getEventImageUrl };\r\n\r\n/**\r\n * Calculate CTA state based on ticket availability\r\n */\r\n/**\r\n * VC's 4-state CTA derivation (available/sold_out/coming_soon/ended) for parsed events.\r\n * Distinct from SC's `calculateCtaState` (richer wire-level canonical) — renamed to\r\n * avoid shadowing the SC export; this variant reads the parsed/raw event shape parseEvent consumes.\r\n */\r\ntype CtaState = 'available' | 'sold_out' | 'coming_soon' | 'ended';\r\n\r\n/**\r\n * Narrow a raw wire string to a known CTA state. The `ctaState`/`cta_state`\r\n * wire fields are loosely typed (`string`), so an unrecognised value (a typo or\r\n * a backend state we don't model) must NOT be trusted verbatim — it falls\r\n * through to the availability-based derivation instead of masquerading as a\r\n * valid state. The switch narrows each literal, so no cast is needed.\r\n */\r\nfunction toCtaState(raw: string): CtaState | null {\r\n  switch (raw) {\r\n    case 'available':\r\n    case 'sold_out':\r\n    case 'coming_soon':\r\n    case 'ended':\r\n      return raw;\r\n    default:\r\n      return null;\r\n  }\r\n}\r\n\r\nexport function deriveEventCtaState(apiEvent: ApiEvent): CtaState {\r\n  // Check explicit CTA state first — but only trust a value we recognise.\r\n  const explicitState = apiEvent.ctaState || apiEvent.cta_state;\r\n  if (explicitState) {\r\n    const known = toCtaState(explicitState);\r\n    if (known) {\r\n      return known;\r\n    }\r\n  }\r\n\r\n  // Check if event is cancelled or ended\r\n  if (apiEvent.isCancelled || apiEvent.is_cancelled) {\r\n    return 'ended';\r\n  }\r\n\r\n  // Check event date\r\n  const eventDate =\r\n    apiEvent.startDateTime || apiEvent.start_date_time || apiEvent.date;\r\n  if (eventDate) {\r\n    const eventTime = new Date(eventDate).getTime(); // @datetime-escape: event-past check — startDateTime/start_date_time are UTC-Z instants (tz-independent); the apiEvent.date fallback is date-only → UTC-midnight parse (near-midnight venue-tz edge) — follow-up dt-vc-eventdate-fallback\r\n    const now = Date.now();\r\n\r\n    if (eventTime < now) {\r\n      return 'ended';\r\n    }\r\n  }\r\n\r\n  // Check ticket availability\r\n  const availableCount =\r\n    apiEvent.ticketsAvailable ?? apiEvent.tickets_available;\r\n\r\n  if (availableCount !== undefined) {\r\n    if (availableCount <= 0) {\r\n      return 'sold_out';\r\n    }\r\n    return 'available';\r\n  }\r\n\r\n  // Check tickets array\r\n  const tickets =\r\n    apiEvent.availableTickets ||\r\n    apiEvent.available_tickets ||\r\n    apiEvent.tickets ||\r\n    [];\r\n\r\n  if (tickets.length === 0) {\r\n    return 'coming_soon';\r\n  }\r\n\r\n  const totalAvailable = tickets.reduce((sum: number, t: any) => {\r\n    const qty = t.quantityAvailable ?? t.quantity_available ?? t.quantity ?? 0;\r\n    const sold = t.quantitySold ?? t.quantity_sold ?? 0;\r\n    return sum + Math.max(0, qty - sold);\r\n  }, 0);\r\n\r\n  if (totalAvailable <= 0) {\r\n    return 'sold_out';\r\n  }\r\n\r\n  return 'available';\r\n}\r\n\r\n/**\r\n * Parse a raw ticket payload into the normalized AvailableTicket domain shape.\r\n *\r\n * Wire shape is contained inside this module. Uses `||` chains matching the\r\n * old transformer exactly -- 0/false values fall through to the next variant\r\n * or default, byte-identical to previous behavior.\r\n */\r\nexport function parseTicket(raw: unknown): AvailableTicket {\r\n  const apiTicket = raw as ApiTicket;\r\n  return {\r\n    id: apiTicket.id || apiTicket.ID,\r\n    name: apiTicket.name || apiTicket.ticketName || '',\r\n    description: apiTicket.description,\r\n    price: apiTicket.price || 0,\r\n    quantity: apiTicket.quantity || apiTicket.totalQuantity || 0,\r\n    quantitySold: apiTicket.quantitySold || apiTicket.quantity_sold || 0,\r\n    quantityAvailable:\r\n      apiTicket.quantityAvailable ||\r\n      apiTicket.quantity_available ||\r\n      (apiTicket.quantity || 0) - (apiTicket.quantitySold || 0),\r\n    minPerOrder: apiTicket.minPerOrder || apiTicket.min_per_order || 1,\r\n    maxPerOrder: apiTicket.maxPerOrder || apiTicket.max_per_order || 10,\r\n    saleStartDate: apiTicket.saleStartDate || apiTicket.sale_start_date,\r\n    saleEndDate: apiTicket.saleEndDate || apiTicket.sale_end_date,\r\n    isHidden: apiTicket.isHidden || apiTicket.is_hidden || false,\r\n    revealWithPromoCode:\r\n      apiTicket.revealWithPromoCode || apiTicket.reveal_with_promo_code,\r\n    ticketType: apiTicket.ticketType || apiTicket.ticket_type || 0,\r\n    sectionId: apiTicket.sectionId || apiTicket.section_id,\r\n    sortOrder: apiTicket.sortOrder || apiTicket.sort_order || 0,\r\n  };\r\n}\r\n\r\n/**\r\n * Parse a raw event payload into the normalized Event domain shape.\r\n *\r\n * Wire shape (ApiEvent) is contained inside this module and never escapes it.\r\n * Uses `||` chains matching the old transformer exactly -- 0/false values fall\r\n * through to the next variant, byte-identical to previous behavior. Throw\r\n * behavior preserved from old mapper: null/undefined input (property access on a nullish value) or a non-array\r\n * tickets field throws exactly as the old code did. Callers always pass real\r\n * wire objects.\r\n *\r\n * COMPOSITION NOTE — passthrough seams (events convergence):\r\n * The trailing block of fields below is carried VERBATIM from the wire (no\r\n * fallback chains, no normalization) so that the view-shape projections —\r\n * `utils/event-transform.js` (DETAIL/BROWSE) and\r\n * `public-calendar-flow/transform.ts` (EventData) — can compose parseEvent\r\n * for every event-level scalar instead of reading the wire themselves.\r\n * `venue`/`performers`/`faqs`/`showtimes`/`purchasedTickets` stay raw objects\r\n * by contract: their consumers (and #260's performer canonical) own that\r\n * variance; normalizing them here would change rendered output.\r\n */\r\nexport function parseEvent(raw: unknown): Event {\r\n  const apiEvent = raw as ApiEvent;\r\n\r\n  // Extract tickets array from various possible field names\r\n  const rawTickets =\r\n    apiEvent.availableTickets ||\r\n    apiEvent.available_tickets ||\r\n    apiEvent.tickets ||\r\n    [];\r\n\r\n  const tickets = rawTickets.map(parseTicket);\r\n\r\n  // Calculate min/max prices from tickets\r\n  const prices = tickets.map(t => t.price).filter(p => p > 0);\r\n  const minPrice = prices.length > 0 ? Math.min(...prices) : undefined;\r\n  const maxPrice = prices.length > 0 ? Math.max(...prices) : undefined;\r\n\r\n  return {\r\n    eventID: apiEvent.eventID || apiEvent.id || apiEvent.ID || 0,\r\n    id: apiEvent.id || apiEvent.ID,\r\n    name: apiEvent.name || apiEvent.title || '',\r\n    title: apiEvent.title || apiEvent.name,\r\n    slug: apiEvent.slug,\r\n    description: apiEvent.description,\r\n    date:\r\n      apiEvent.date || apiEvent.startDateTime || apiEvent.start_date_time || '',\r\n    startDateTime: apiEvent.startDateTime || apiEvent.start_date_time,\r\n    endDateTime: apiEvent.endDateTime || apiEvent.end_date_time,\r\n    doorsOpenTime: apiEvent.doorsOpenTime || apiEvent.doors_open_time,\r\n    timezone: apiEvent.timezone || apiEvent.time_zone,\r\n    venueId: apiEvent.venueId || apiEvent.venue_id,\r\n    venueName: apiEvent.venueName || apiEvent.venue_name,\r\n    venueAddress: apiEvent.venueAddress || apiEvent.venue_address,\r\n    location:\r\n      apiEvent.location || apiEvent.venueAddress || apiEvent.venue_address,\r\n    imageUrl: getEventImageUrlByFieldPrecedence(apiEvent),\r\n    imageURL: getEventImageUrlByFieldPrecedence(apiEvent),\r\n    status: apiEvent.status,\r\n    isPublished: apiEvent.isPublished ?? apiEvent.is_published,\r\n    isCancelled: apiEvent.isCancelled ?? apiEvent.is_cancelled,\r\n    availableTickets: tickets,\r\n    ticketsAvailable:\r\n      apiEvent.ticketsAvailable ??\r\n      apiEvent.tickets_available ??\r\n      tickets.reduce((sum, t) => sum + (t.quantityAvailable || 0), 0),\r\n    ticketsSold: apiEvent.ticketsSold ?? apiEvent.tickets_sold,\r\n    minPrice: apiEvent.minPrice ?? apiEvent.min_price ?? minPrice,\r\n    maxPrice: apiEvent.maxPrice ?? apiEvent.max_price ?? maxPrice,\r\n    ctaText: apiEvent.ctaText || apiEvent.cta_text,\r\n    ctaState: deriveEventCtaState(apiEvent),\r\n    showPerformers: apiEvent.showPerformers ?? apiEvent.show_performers,\r\n    eventSeriesId: apiEvent.eventSeriesId || apiEvent.event_series_id,\r\n    seriesInstanceNumber:\r\n      apiEvent.seriesInstanceNumber || apiEvent.series_instance_number,\r\n    // ── Passthrough seams (see composition note above) — verbatim wire ──\r\n    timeZone: apiEvent.timeZone,\r\n    eventSummary: apiEvent.eventSummary,\r\n    password: apiEvent.password,\r\n    hasPassword: apiEvent.hasPassword,\r\n    disclaimer: apiEvent.disclaimer,\r\n    ticketType: apiEvent.ticketType,\r\n    eventTicketingType: apiEvent.eventTicketingType,\r\n    ageRestriction: apiEvent.ageRestriction,\r\n    displayAgeRestriction: apiEvent.displayAgeRestriction,\r\n    displayStartTime: apiEvent.displayStartTime,\r\n    displayEndTime: apiEvent.displayEndTime,\r\n    displayDoorsTime: apiEvent.displayDoorsTime,\r\n    collectionId: apiEvent.collectionId || apiEvent.collection_id,\r\n    ticketsRemaining: apiEvent.ticketsRemaining,\r\n    ticketsTotal: apiEvent.ticketsTotal,\r\n    hasHiddenTickets: apiEvent.hasHiddenTickets,\r\n    stage: apiEvent.stage,\r\n    stageName: apiEvent.stageName,\r\n    stageId: apiEvent.stageId,\r\n    eventCategoryTypes: apiEvent.eventCategoryTypes,\r\n    publicPerformers: apiEvent.publicPerformers,\r\n    collectionIds: apiEvent.collectionIds,\r\n    venue: apiEvent.venue,\r\n    performers: apiEvent.performers,\r\n    faqs: apiEvent.faqs,\r\n    showtimes: apiEvent.showtimes,\r\n    purchasedTickets: apiEvent.purchasedTickets,\r\n  };\r\n}\r\n\r\n/**\r\n * Back-compat alias -- existing call sites using transformTicket continue\r\n * to work unchanged.\r\n */\r\nexport const transformTicket = parseTicket;\r\n\r\n/**\r\n * Back-compat alias -- existing call sites using transformEvent(apiEvent)\r\n * continue to work unchanged.\r\n */\r\nexport const transformEvent = parseEvent;\r\n\r\n/**\r\n * Legacy transformer name for backwards compatibility.\r\n */\r\nexport const transformEventData = parseEvent;\r\n\r\nexport function parseEventList(raws: unknown[]): Event[] {\r\n  return raws.map(parseEvent);\r\n}\r\n","/**\r\n * Venue Transformer\r\n *\r\n * Normalizes API venue responses to a consistent format.\r\n *\r\n * Wire->domain boundary: one parseVenue(raw: unknown) entry point.\r\n * The wire field shape (ApiVenue) is named only inside this module and never\r\n * escapes it. Above the boundary only the Venue domain type.\r\n *\r\n * IMPLEMENTATION NOTE -- why no Zod schema here:\r\n * The old mapper used `||` for id/name (0 falls through) and `??` for fee fields\r\n * (0 fee is a real value, must NOT fall through). Both operators replicated verbatim.\r\n * Throw behavior is identical to the old mapper: null/undefined input (property access on a nullish value) throws exactly\r\n * as the old code did. Callers always pass real wire objects.\r\n */\r\n\r\nimport { resolveImageUrl } from '@getmicdrop/svelte-components';\r\nimport type { Venue } from '../types.js';\r\n\r\n// ── Wire shape (internal -- never exported) ──────────────────────────────\r\ninterface ApiVenue {\r\n  id?: number;\r\n  ID?: number;\r\n  name?: string;\r\n  slug?: string;\r\n  address?: string;\r\n  googleLocationNameCache?: string;\r\n  google_location_name_cache?: string;\r\n  city?: string;\r\n  state?: string;\r\n  zipCode?: string;\r\n  zip_code?: string;\r\n  country?: string;\r\n  timezone?: string;\r\n  time_zone?: string;\r\n  logoUrl?: string;\r\n  logo_url?: string;\r\n  logo?: string;\r\n  serviceFeePercentage?: number;\r\n  service_fee_percentage?: number;\r\n  serviceFeeCents?: number;\r\n  service_fee_cents?: number;\r\n  taxPercentage?: number;\r\n  tax_percentage?: number;\r\n  organizationId?: number;\r\n  organization_id?: number;\r\n}\r\n\r\n/**\r\n * Get the CDN image URL for a venue logo.\r\n *\r\n * Delegates the host-join to SC's canonical `resolveImageUrl` with the\r\n * Cloudflare-fronted CDN base (`moxy.sfo3.cdn`) — the same correct, edge-cached\r\n * host every other VC public surface uses. Replaced VC's local `micdrop-images`\r\n * bucket, which 404s for real keys (CDN census 2026-07-05).\r\n */\r\nfunction getLogoUrl(path: string | undefined): string {\r\n  return resolveImageUrl(path, { cdn: true });\r\n}\r\n\r\n/**\r\n * Parse a raw venue payload into the normalized Venue domain shape.\r\n *\r\n * Wire shape (ApiVenue) is contained inside this module and never escapes it.\r\n * Uses `||` / `??` chains matching the old transformer exactly -- byte-identical\r\n * to previous behavior. Throw behavior preserved from old mapper: null/undefined\r\n * input throws exactly as the old code did. Callers always pass real wire objects.\r\n */\r\n// Compare-first vs SC canonical parseVenue(raw): unknown => ParsedVenue:\r\n// GENUINELY DIVERGED — different return shape. SC returns a `ParsedVenue` whose\r\n// `logoPath` is the raw path (and accepts extra fallback keys: image,\r\n// squareImageUrl, postalCode), leaving URL resolution to the caller; VC returns\r\n// the `Venue` domain type with an already-resolved `logoUrl: getLogoUrl(path)`\r\n// and `timezone` (not SC's `timeZone`). Kept local under a non-shadowing name\r\n// and re-exported under the public name; no eslint-disable.\r\nfunction vcParseVenue(raw: unknown): Venue {\r\n  const apiVenue = raw as ApiVenue;\r\n\r\n  const logoPath = apiVenue.logoUrl || apiVenue.logo_url || apiVenue.logo;\r\n\r\n  return {\r\n    id: apiVenue.id || apiVenue.ID || 0,\r\n    name: apiVenue.name || '',\r\n    slug: apiVenue.slug,\r\n    address: apiVenue.address,\r\n    googleLocationNameCache:\r\n      apiVenue.googleLocationNameCache || apiVenue.google_location_name_cache,\r\n    city: apiVenue.city,\r\n    state: apiVenue.state,\r\n    zipCode: apiVenue.zipCode || apiVenue.zip_code,\r\n    country: apiVenue.country,\r\n    timezone: apiVenue.timezone || apiVenue.time_zone,\r\n    logoUrl: getLogoUrl(logoPath),\r\n    serviceFeePercentage:\r\n      apiVenue.serviceFeePercentage ?? apiVenue.service_fee_percentage ?? 0,\r\n    serviceFeeCents:\r\n      apiVenue.serviceFeeCents ?? apiVenue.service_fee_cents ?? 0,\r\n    taxPercentage: apiVenue.taxPercentage ?? apiVenue.tax_percentage ?? 0,\r\n    organizationId: apiVenue.organizationId || apiVenue.organization_id,\r\n  };\r\n}\r\n\r\n/**\r\n * Public re-export under the canonical name + back-compat alias. Existing call\r\n * sites using either parseVenue(apiVenue) or transformVenue(apiVenue) continue\r\n * to work unchanged; re-exports don't redeclare the identifier so the\r\n * no-shadowed-helper rule is satisfied without a suppression.\r\n */\r\nexport { vcParseVenue as parseVenue };\r\nexport const transformVenue = vcParseVenue;\r\n\r\n/**\r\n * Extract fee configuration from a raw venue payload.\r\n *\r\n * Uses `??` (not `||`) so 0-valued fees are preserved correctly.\r\n */\r\n// Compare-first vs SC canonical extractVenueFees(raw): unknown => VenueFees:\r\n// GENUINELY DIVERGED — VC returns an inline object literal type derived from its\r\n// own ApiVenue wire shape (with VC's snake/camel casing fallbacks), not SC's\r\n// branded `VenueFees`. Kept local under a non-shadowing name and re-exported\r\n// below; no eslint-disable.\r\nfunction vcExtractVenueFees(raw: unknown): {\r\n  serviceFeePercentage: number;\r\n  serviceFeeCents: number;\r\n  taxPercentage: number;\r\n} {\r\n  const apiVenue = raw as ApiVenue;\r\n  return {\r\n    serviceFeePercentage:\r\n      apiVenue.serviceFeePercentage ?? apiVenue.service_fee_percentage ?? 0,\r\n    serviceFeeCents:\r\n      apiVenue.serviceFeeCents ?? apiVenue.service_fee_cents ?? 0,\r\n    taxPercentage: apiVenue.taxPercentage ?? apiVenue.tax_percentage ?? 0,\r\n  };\r\n}\r\n\r\n/**\r\n * Get formatted venue address.\r\n *\r\n * Compare-first vs SC canonical formatVenueAddress(venue: Pick<ParsedVenue,\r\n * 'address'|'city'|'state'|...>): GENUINELY DIVERGED — VC takes its own `Venue`\r\n * domain type (the resolved shape `vcParseVenue` emits), not SC's `ParsedVenue`\r\n * pick. Kept local under a non-shadowing name and re-exported below; no\r\n * eslint-disable.\r\n */\r\nfunction vcFormatVenueAddress(venue: Venue): string {\r\n  const parts = [venue.address, venue.city, venue.state, venue.zipCode].filter(\r\n    Boolean\r\n  );\r\n\r\n  return parts.join(', ');\r\n}\r\n\r\nexport {\r\n  vcExtractVenueFees as extractVenueFees,\r\n  vcFormatVenueAddress as formatVenueAddress,\r\n};\r\n"],"names":["logger","createLogger","DEFAULT_CONFIG","error","globalConfig","configureApi","config","getApiConfig","getPublicBaseUrl","getLegacyPublicUrl","getOrdersV2Url","getClientIP","sleep","ms","resolve","fetchWithRetry","url","init","cfg","method","maxAttempts","lastError","attempt","controller","timeoutId","callerSignal","onCallerAbort","response","err","apiGet","endpoint","options","apiRequest","apiPost","body","apiPut","apiDelete","errorData","message","errorMessage","simpleFetch","parseCartReservation","raw","rec","parseCart","data","uuid","eventID","status","expiresAt","reservations","UTM_KEYS","UTM_PARAM","DIRECT_SOURCE","normalizeUtmValue","normalizeUtmSet","out","key","readUtmSet","params","isTopLevel","resolveHostContext","hasWindow","topLevel","search","referrer","pageUrl","granted","hasTcf","isConsentRequired","isConsentGranted","SESSION_ID_KEY","VISITOR_ID_KEY","UUID_V4","isUuidV4","value","generateUuidV4","cryptoObj","bytes","i","hex","getSessionId","id","getSessionStorage","setSessionStorage","getVisitorId","stored","getLocalStorage","setLocalStorage","ATTRIBUTION_KEY","readStore","getAttribution","touch","createPaymentIntent","cartId","quantities","donationAmounts","apiResult","AppError","getCartByUUID","cartUUID","expectedEventID","updateCartQuantities","numericQuantities","k","v","n","numericDonations","completeReservation","orderUuid","cancelReservation","createOrder","eventId","promoCode","getOrder","orderId","validatePaymentIntent","payload","result","extendCheckoutSession","getSessionStatus","initiateOrder","cartData","trackUTMSource","venueId","urlParams","utmSource","ORDERS_V2_PUBLIC","validatePromoCode","code","encodedCode","hasPromoCodes","applyPromoCode","removePromoCode","parseEventPerformers","ok","errNotFound","isOk","isErr","unwrapOr","fallback","_eventDetailsInflight","fetchEventDetailsResult","customFetch","password","inflight","run","fetchEventDetails","loadResult","errorCode","map","asArray","fetchEventTicketsResult","fetchEventTickets","fetchEventPerformersResult","fetchEventPerformers","fetchAllVenuesResult","orgId","fetchAllVenues","fetchVenueEventsResult","fetchVenueEvents","unwrapMonthEvents","getMonthEventsResult","year","month","getMonthEvents","getOrgMonthEventsResult","getOrgMonthEvents","getSeriesOccurrencesResult","eventSeriesId","getSeriesOccurrences","fetchSeriesOccurrencesResult","fetchSeriesOccurrences","resolvePublicEntity","slug","qs","fetchSeriesPage","seriesId","fetchPublicCollection","collectionId","checkCollectionPassword","checkEventPassword","testNetworkConnection","getVenue","getVenueFees","venue","getVenueBySlug","encodedSlug","parseGiftCardApplication","giftCardAmountDollars","residualDollars","fullyCovered","requiresStripe","API_BASE_URL","ORDERS_V2_URL","createGiftCardPurchase","req","applyGiftCard","removeGiftCard","completeGiftCardPayment","customerDetails","WAITLIST_ERROR_MESSAGES","joinWaitlist","email","phone","smsOptIn","validateWaitlistToken","token","getWaitlistStatus","computeCtaState","event","tickets","cancelled","isRegistration","waitlistEnabled","now","eventEnd","hiddenAvailable","isHiddenTicketPurchasable","publicTickets","t","hasPurchasable","allSoldOut","allComingSoon","earliestSalesStart","ticket","salesBegin","salesEnd","remaining","isSoldOut","isScheduled","hasSalesEnded","startDate","diffMs","diffHours","diffDays","timeLabel","d","formatLocal","dateText","parsePurchasedTicket","apiTicket","parseOrder","apiOrder","rawTickets","transformTicket","transformOrder","transformOrderForDisplay","order","displayId","rawTotal","formatCurrency","asUSD","getCDNImageUrl","path","resolveImageUrl","getEventImageUrlByFieldPrecedence","apiEvent","rawUrl","toCtaState","deriveEventCtaState","explicitState","known","eventDate","eventTime","availableCount","sum","qty","sold","parseTicket","parseEvent","prices","p","minPrice","maxPrice","transformEvent","transformEventData","getLogoUrl","vcParseVenue","apiVenue","logoPath","transformVenue","vcExtractVenueFees","vcFormatVenueAddress"],"mappings":"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"}