import { EventTicketInput, HostSeoControllerOptions } from './types';
/**
* One show, as the listing hands it over.
*
* It used to be id/name/slug/startDateTime/image, because the ItemList it fed
* published nothing but a position and a URL. Everything below the image is
* what `buildEventJsonLd` needs to describe a show to a search engine — the
* end time, whether it is cancelled, what it costs, where it is. Every field
* is optional: an event that cannot be described falls back to a bare
* `ListItem` with a URL on it, exactly as before.
*/
interface ListingEvent {
id: number | string;
name: string;
slug?: string;
startDateTime?: string;
endDateTime?: string;
image?: string;
status?: string;
description?: string;
eventSummary?: string;
availableTickets?: EventTicketInput[];
/** The show's own zone, when it differs from the venue's. */
timeZone?: string;
/** The show's own venue, on a calendar that spans several. */
showVenue?: ShowVenue;
}
/**
* The venue one show plays at. A multi-venue calendar has no controller-wide
* venue, so each show brings its own; it is read per show and never written
* back to the controller, which every calendar on the page shares.
*/
interface ShowVenue {
name: string;
/** One-line address. Empty publishes the venue name alone. */
address?: string;
timeZone?: string;
}
interface VenueData {
name: string;
address?: string;
googleLocationNameCache?: string;
timeZone?: string;
timezone?: string;
}
export declare class HostSeoController {
/**
* Single active instance: two controllers would fight to own
* `
`/OG/etc, so constructing one destroys the one before it.
* Embeds go through `shared()` instead, so every calendar on a page with
* several (e.g. "upcoming shows" + "this weekend") drives the same one.
*/
static _activeInstance: HostSeoController | null;
/** The page's live controller, or a new one when there is none. Each
* caller holds it until its own destroy(); the last one out tears it down. */
static shared(options: HostSeoControllerOptions): HostSeoController;
private _state;
private _holders;
private _venueName;
private _venueAddress;
private _venueTimeZone;
private _baseUrl;
/**
* Origin of the Micdrop site that server-renders `/e/{id}-{slug}`.
*
* This is the ONLY per-show URL in existence that a search engine can index:
* the host page has exactly one URL however many shows the widget draws on
* it. Empty means "not configured" — the structured data then points back at
* the host page and the shows are, for indexing purposes, invisible.
*/
private _publicSiteOrigin;
private _originals;
private _originalsSaved;
private _events;
constructor(options: HostSeoControllerOptions);
private _saveOriginals;
private _injectJsonLd;
private _setMeta;
private _setCanonical;
/**
* The canonical for the "one show open" state: the host page's own.
*
* A page that already declares a canonical keeps it untouched — the host
* knows its own address better than we do (params it strips, a www variant it
* has settled on). One that declares none gets its bare address, never a
* query-string variant of it: the `?e={id}-{slug}` shape this replaces was a
* distinct URL to a crawler that RENDERED THE LISTING while the canonical
* claimed it was a show, which is the worst of the available answers.
*/
private _setEntityCanonical;
private _removeAllInjected;
private _restoreOriginals;
private _restoreMetaProperty;
private _restoreMetaName;
/**
* The canonical, server-rendered Micdrop page for one show:
* `{publicSiteOrigin}/e/{id}-{slug}`.
*
* This is what "a real link to a show" has to mean for a script embed. A
* search engine indexes URLs, and the host page has ONE — a link that only
* changes the host page's query string or fragment adds no show to any index,
* whatever it renders. `/e/{id}-{slug}` is a micdrop-frontend route that
* server-renders the show, so it is both crawlable without JavaScript and the
* page a buyer can finish an order on.
*
* Falls back to the in-place deep link when no public site origin is
* configured — a wrong origin would publish 404s, which is worse than
* publishing the host page.
*/
private _showPageUrl;
/**
* The host-page URL that re-opens this entity in place: `{host page}#{id}-{slug}`.
*
* THE HASH, NOT A QUERY PARAM, AND THAT IS THE WHOLE OF THIS FUNCTION. Every
* URL this controller published used to be `{host page}?e={id}-{slug}` (or
* `?s=` / `?c=`), and the embed does not read `?e=`: `parseDeepLink` in
* VenueCalendar.js reads `window.location.hash`, and `WidgetUrlManager`
* writes it. The only place `?e=` is handled at all is the hosted SvelteKit
* app's `routes/+page.svelte`, which is a different origin from any venue's
* site. So the canonical URL, the `og:url` and every ItemList entry named a
* URL that opened the LISTING — never the show it claimed to be.
*/
private _entityDeepLink;
/**
* ItemList for the listing, with each show's own structured data nested in
* its ListItem.
*
* It used to publish a position and a URL per show and nothing else, which
* told a search engine that N things exist and not one fact about any of
* them. Each item now carries the full `Event` object — name, start, venue,
* postal address, offers, image — through the same builder the entity view
* and micdrop-frontend's own hosted site pages use, so the listing and the
* show page cannot describe the same show differently.
*
* An event `buildEventJsonLd` refuses (no name, no start, no venue name)
* degrades to the bare `ListItem` + `url` shape rather than emitting a
* half-built Event: an incomplete Event is a structured-data error, an
* unadorned ListItem is merely quiet.
*/
private _buildItemList;
/**
* The venue and zone one show is published with: its own when it carries
* one, the controller-wide venue otherwise.
*/
private _venueFor;
/**
* The URL for the entity the visitor has open: the canonical Micdrop show
* page when one exists, so `og:url` and `` name a page
* that actually renders this show rather than the host page's listing.
*
* Series and collections have no `/e/` page of their own, so they keep the
* in-place deep link — a link that reopens them where the visitor is, which
* is at least true.
*/
private _buildEntityUrl;
/**
* Called when events finish loading from the API.
* Injects an ItemList JSON-LD for the listing. Does not modify OG/canonical/title.
*/
onEventsLoaded(events: ListingEvent[], venue?: VenueData): void;
/**
* Called when the user selects an event, series, or collection.
* Replaces ItemList JSON-LD with entity-specific JSON-LD and updates
* all head tags (canonical, OG, meta description, title).
*/
onEntitySelected(type: 'event' | 'series' | 'collection', data: any, venue?: VenueData): void;
/**
* Called when the user navigates back to the event listing.
* Restores original head elements and re-injects ItemList JSON-LD.
*/
onBackToListing(): void;
/**
* Called when the widget is destroyed. Removes all injected elements
* and restores originals. Clears the static active instance.
*/
destroy(): void;
private _teardown;
}
export {};