@burdenoff/website-sdk 2026.829.2 → 2026.829.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/explore.js +86 -2
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +87 -3
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +22 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +22 -1
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +86 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{use-explore-chat-8eL7WdLc.d.mts → use-explore-chat-B-E7jN1H.d.mts} +5 -0
- package/dist/{use-explore-chat-8eL7WdLc.d.ts → use-explore-chat-B-E7jN1H.d.ts} +5 -0
- package/package.json +1 -1
package/dist/hooks/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/security.ts","../../src/client/graphql-client.ts","../../src/client/provider.tsx","../../src/components/explore-types.ts","../../src/data/products.ts","../../src/utils/recaptcha-v3.ts","../../src/hooks/use-explore-chat.ts","../../src/hooks/use-speech-input.ts"],"names":["useMemo","useState","useRef","useCallback","useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["const LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\"]);\nconst RESERVED_HEADERS = new Set([\n \"authorization\",\n \"cookie\",\n \"x-actor-id\",\n \"x-actor-type\",\n \"x-consent-granted-by\",\n \"x-consent-scope\",\n \"x-consent-granted-at\",\n \"x-consent-expires-at\",\n]);\n\nexport function validateGatewayUrl(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Gateway URL must be a valid absolute URL\");\n }\n\n if (url.protocol === \"https:\") {\n return url.toString();\n }\n\n if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n return url.toString();\n }\n\n throw new Error(\"Gateway URL must use HTTPS unless it targets localhost\");\n}\n\nexport function sanitizeHeaders(\n headers?: Record<string, string>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([key]) => !RESERVED_HEADERS.has(key.toLowerCase()),\n ),\n );\n}\n\n/**\n * Hostnames whose Cloudflare Access application gates the GraphQL gateway.\n *\n * Only the alpha gateways are gated; the production gateways are public, so a token is never\n * attached there even if one is configured.\n */\nconst CF_ACCESS_GATED_HOSTS = new Set([\n \"alphagraphql.burdenoff.com\",\n \"alphagraphqlworkspaces.burdenoff.com\",\n]);\n\n/**\n * Service-token headers for a gated gateway, or nothing.\n *\n * Returns an empty object unless the target really is a gated host AND both halves of the token\n * are present — a half-configured token would send a malformed credential to every request.\n */\nexport function cfAccessHeaders(\n gatewayUrl: string,\n cfAccess?: { clientId?: string; clientSecret?: string },\n): Record<string, string> {\n const clientId = cfAccess?.clientId?.trim();\n const clientSecret = cfAccess?.clientSecret?.trim();\n if (!clientId || !clientSecret) return {};\n\n let host: string;\n try {\n host = new URL(gatewayUrl).hostname.toLowerCase();\n } catch {\n return {};\n }\n if (!CF_ACCESS_GATED_HOSTS.has(host)) return {};\n\n return {\n \"CF-Access-Client-Id\": clientId,\n \"CF-Access-Client-Secret\": clientSecret,\n };\n}\n","/**\n * Lightweight GraphQL client for the Burdenoff Web SDK.\n * Uses native fetch - zero external dependencies.\n * All calls are unauthenticated (public gateway operations only).\n */\n\nimport {\n cfAccessHeaders,\n sanitizeHeaders,\n validateGatewayUrl,\n} from \"./security\";\n\nexport interface WebSDKClientConfig {\n /** Global public gateway URL (e.g. \"https://api.burdenoff.com/global/graphql\") */\n gatewayUrl: string;\n /** Platform product ID for scoping operations */\n productId: string;\n /** Product slug (used for public product queries) */\n productSlug?: string;\n /** reCAPTCHA site key (if not fetched from product config) */\n recaptchaSiteKey?: string;\n /** Rybbit analytics site ID */\n rybbitSiteId?: string;\n /** Custom headers to include in all requests */\n headers?: Record<string, string>;\n /**\n * Cloudflare Access service token, for the ALPHA gateway hosts only.\n *\n * `alphagraphql.burdenoff.com` sits behind a Cloudflare Access application, so an\n * unauthenticated browser XHR is answered with a 302 to the Access login on a different\n * origin — which the browser reports as an opaque CORS failure rather than a 401. Attaching\n * the service-token headers is how every app shell already passes that gate (fe-libs\n * `installGatewayFetchRewrite`); the website SDK previously had no equivalent, so contact,\n * newsletter, waitlist and explore all failed on alpha.\n *\n * Vite only inlines `VITE_*` into APP source, never into a bundled library, so the host app\n * must read `import.meta.env` and pass the values in. Production gateways are not gated and\n * receive no headers.\n */\n cfAccess?: { clientId?: string; clientSecret?: string };\n /**\n * Per-request timeout in ms. Kept below the gateway's operation timeout so a\n * stalled request surfaces as an error the UI can render, instead of leaving\n * a page stuck on loading skeletons forever. Default 12000.\n */\n timeoutMs?: number;\n /**\n * Extra attempts for transient failures (timeout / network / 5xx / 429) on\n * QUERIES ONLY. Mutations are never retried — a retried contact-form or\n * waitlist submit would double-submit. Default 1 (2 attempts total).\n */\n maxRetries?: number;\n}\n\n/**\n * Per-call overrides for {@link WebSDKClient.query}.\n *\n * The defaults (5-minute response cache + in-flight deduplication) are right\n * for the read-once content queries most SDK components make, and wrong for a\n * poll loop: the second poll of the same `(query, variables)` pair would be\n * served straight from the cache and the UI would freeze on the first\n * response forever. Pass `{ cache: false }` for anything polled.\n */\nexport interface WebSDKQueryOptions {\n /**\n * Use the response cache and in-flight deduplication. Default `true`.\n * `false` skips the cache read, the dedupe map AND the cache write, so the\n * call always hits the network and never poisons a later cached read.\n */\n cache?: boolean;\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\n/** Per-call overrides for {@link WebSDKClient.mutate}. */\nexport interface WebSDKMutateOptions {\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data?: T;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: Array<string | number>;\n extensions?: Record<string, unknown>;\n }>;\n}\n\nexport class WebSDKClient {\n private config: WebSDKClientConfig;\n private queryCache = new Map<\n string,\n { data: GraphQLResponse<unknown>; ts: number }\n >();\n private inflight = new Map<string, Promise<GraphQLResponse<unknown>>>();\n private static CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n private static MAX_CACHE_ENTRIES = 100;\n private static DEFAULT_TIMEOUT_MS = 12_000;\n private static DEFAULT_MAX_RETRIES = 1;\n private static RETRY_BASE_DELAY_MS = 400;\n\n constructor(config: WebSDKClientConfig) {\n this.config = {\n ...config,\n gatewayUrl: validateGatewayUrl(config.gatewayUrl),\n headers: sanitizeHeaders(config.headers),\n };\n }\n\n getConfig(): WebSDKClientConfig {\n return this.config;\n }\n\n /**\n * Execute a GraphQL query (with deduplication and caching).\n *\n * Pass `{ cache: false }` to bypass the cache entirely — required for poll\n * loops, where every tick must reach the network.\n */\n async query<T = Record<string, unknown>>(\n query: string,\n variables?: Record<string, unknown>,\n options?: WebSDKQueryOptions,\n ): Promise<GraphQLResponse<T>> {\n // Uncached path: no cache read, no in-flight dedupe, no cache write.\n // Deliberately bypasses the dedupe map too — two identical polls issued a\n // few hundred ms apart must both hit the network, otherwise the second one\n // resolves with the first one's (already stale) snapshot.\n if (options?.cache === false) {\n return this.request<T>(query, variables, true, options.timeoutMs);\n }\n\n const cacheKey = JSON.stringify({ query, variables });\n\n // Return cached response if still valid, evict if expired\n const cached = this.queryCache.get(cacheKey);\n if (cached) {\n if (Date.now() - cached.ts < WebSDKClient.CACHE_TTL) {\n return cached.data as GraphQLResponse<T>;\n }\n this.queryCache.delete(cacheKey);\n }\n\n // Deduplicate: if same query is already in-flight, reuse the promise\n const existing = this.inflight.get(cacheKey);\n if (existing) {\n return existing as Promise<GraphQLResponse<T>>;\n }\n\n const promise = this.request<T>(query, variables, true, options?.timeoutMs)\n .then((result) => {\n // Cache successful responses only\n if (result.data && !result.errors?.length) {\n if (this.queryCache.size >= WebSDKClient.MAX_CACHE_ENTRIES) {\n const oldestEntry = this.queryCache.keys().next().value;\n if (oldestEntry) {\n this.queryCache.delete(oldestEntry);\n }\n }\n this.queryCache.set(cacheKey, { data: result, ts: Date.now() });\n }\n return result;\n })\n .finally(() => {\n this.inflight.delete(cacheKey);\n });\n\n this.inflight.set(cacheKey, promise);\n return promise;\n }\n\n /**\n * Execute a GraphQL mutation\n */\n async mutate<T = Record<string, unknown>>(\n mutation: string,\n variables?: Record<string, unknown>,\n options?: WebSDKMutateOptions,\n ): Promise<GraphQLResponse<T>> {\n // retry=false: a retried mutation could double-submit (contact form,\n // waitlist signup, order). Only the timeout applies here.\n return this.request<T>(mutation, variables, false, options?.timeoutMs);\n }\n\n /** HTTP statuses worth another attempt — transient server/edge conditions. */\n private static isRetriableStatus(status: number): boolean {\n return status === 429 || status === 408 || (status >= 500 && status < 600);\n }\n\n private static sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Perform the HTTP call with a hard timeout. Every outcome resolves to a\n * GraphQLResponse — callers never hang, so a UI's `loading` state always\n * settles into data or a renderable error.\n */\n private async attempt<T>(\n query: string,\n variables: Record<string, unknown> | undefined,\n timeoutMs: number,\n ): Promise<{ res: GraphQLResponse<T>; retriable: boolean }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(this.config.gatewayUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-product-id\": this.config.productId,\n ...this.config.headers,\n ...cfAccessHeaders(this.config.gatewayUrl, this.config.cfAccess),\n },\n body: JSON.stringify({ query, variables }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n console.error(\n \"[WebSDK] GraphQL request failed\",\n response.status,\n response.statusText,\n );\n return {\n res: {\n errors: [\n {\n message: `HTTP ${response.status}: ${response.statusText}`,\n extensions: { code: `HTTP_${response.status}` },\n },\n ],\n },\n retriable: WebSDKClient.isRetriableStatus(response.status),\n };\n }\n\n return {\n res: (await response.json()) as GraphQLResponse<T>,\n retriable: false,\n };\n } catch (error) {\n const aborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || controller.signal.aborted);\n const message = aborted\n ? `Request timed out after ${timeoutMs}ms`\n : error instanceof Error\n ? error.message\n : \"Network error\";\n console.error(\"[WebSDK] Network error\", message);\n return {\n res: {\n errors: [\n {\n message,\n extensions: { code: aborted ? \"TIMEOUT\" : \"NETWORK_ERROR\" },\n },\n ],\n },\n // Transport-level failures are worth one more try; a genuine outage\n // just fails twice quickly and still renders an error state.\n retriable: true,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async request<T>(\n query: string,\n variables?: Record<string, unknown>,\n retry = true,\n timeoutOverrideMs?: number,\n ): Promise<GraphQLResponse<T>> {\n const timeoutMs =\n timeoutOverrideMs ??\n this.config.timeoutMs ??\n WebSDKClient.DEFAULT_TIMEOUT_MS;\n const maxRetries = retry\n ? (this.config.maxRetries ?? WebSDKClient.DEFAULT_MAX_RETRIES)\n : 0;\n\n let last: GraphQLResponse<T> | undefined;\n for (let i = 0; i <= maxRetries; i++) {\n const { res, retriable } = await this.attempt<T>(\n query,\n variables,\n timeoutMs,\n );\n if (!retriable || i === maxRetries) return res;\n last = res;\n // Small backoff with jitter so a burst of clients doesn't retry in lockstep.\n await WebSDKClient.sleep(\n WebSDKClient.RETRY_BASE_DELAY_MS * (i + 1) + Math.random() * 200,\n );\n }\n return last as GraphQLResponse<T>;\n }\n}\n","/**\n * React context provider for the Web SDK client.\n * Wraps the application with WebSDKClient configuration.\n */\n\"use client\";\n\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport { resolveGatewayUrl } from \"./gateway-resolver\";\nimport { WebSDKClient, type WebSDKClientConfig } from \"./graphql-client\";\n\nconst WebSDKContext = createContext<WebSDKClient | null>(null);\n\nexport interface WebSDKProviderProps {\n /** SDK client configuration */\n config: WebSDKClientConfig;\n /** Child components */\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the WebSDKClient available to all child components.\n *\n * @example\n * ```tsx\n * <WebSDKProvider config={{\n * gatewayUrl: \"https://api.burdenoff.com/global/graphql\",\n * productId: \"your-product-id\",\n * productSlug: \"your-product\",\n * }}>\n * <App />\n * </WebSDKProvider>\n * ```\n */\nexport function WebSDKProvider({ config, children }: WebSDKProviderProps) {\n const client = useMemo(() => {\n const resolvedConfig = {\n ...config,\n gatewayUrl: resolveGatewayUrl(config.gatewayUrl),\n };\n return new WebSDKClient(resolvedConfig);\n }, [config]);\n\n return (\n <WebSDKContext.Provider value={client}>{children}</WebSDKContext.Provider>\n );\n}\n\n/**\n * Hook to access the WebSDKClient instance.\n * Must be used within a WebSDKProvider.\n */\nexport function useWebSDK(): WebSDKClient {\n const client = useContext(WebSDKContext);\n if (!client) {\n throw new Error(\"useWebSDK must be used within a WebSDKProvider\");\n }\n return client;\n}\n\n/**\n * Hook to access the SDK configuration.\n * Useful for components that need config values like productId, recaptchaSiteKey, etc.\n */\nexport function useWebSDKConfig(): WebSDKClientConfig {\n const client = useWebSDK();\n return client.getConfig();\n}\n","/**\n * Explore chat — TypeScript mirror of the public `/explore` GraphQL contract.\n *\n * Canonical source: `~/products/dev/platform/context/explore/CONTRACT.md` §1\n * (global-support-svc, served through the global PUBLIC gateway with\n * `@rbac(public: true, scopeType: \"global\")`).\n *\n * Nothing in this file may drift from that document. If a shape here looks\n * wrong, fix CONTRACT.md first and tell the backend workstreams — never patch\n * it locally.\n *\n * Nullability note: the contract marks `title`, `description`, `product`,\n * `imageUrl`, `partialContent`, `errorCode`, `completedAt`, `productSlug`,\n * `recaptchaSiteKey` and `remainingToday` as nullable, so every one of them is\n * `?: T | null` here — a GraphQL `null` and an omitted selection both have to\n * be representable.\n */\n\n// ============================================================================\n// Enums (string unions — the wire format is the enum name)\n// ============================================================================\n\nexport type ExploreMessageRole = \"USER\" | \"ASSISTANT\";\n\nexport type ExploreMessageStatus =\n \"PENDING\" | \"RUNNING\" | \"COMPLETED\" | \"FAILED\";\n\n/**\n * The `ExploreCta.kind` values enumerated in CONTRACT.md §1.\n *\n * `ExploreCtaLink.kind` is deliberately typed `string`, not this union: the\n * field is `String!` on the wire, and a kind added server-side must render\n * (falling back to the neutral CTA style) rather than break the build of 38\n * websites. Use this union when you are *producing* a kind.\n */\nexport type ExploreCtaKind =\n | \"CONTACT\"\n | \"PARTNERS\"\n | \"PRICING\"\n | \"SERVICES\"\n | \"WAITLIST\"\n | \"STORE\"\n | \"APP\"\n | \"DOCS\"\n | \"OTHER\";\n\n/**\n * Error codes surfaced through `extensions.code`. `HTTP_429` is what the\n * gateway emits when it rate-limits at the edge; the SDK client also produces\n * `TIMEOUT` / `NETWORK_ERROR` for transport failures.\n */\nexport type ExploreErrorCode =\n | \"EXPLORE_DISABLED\"\n | \"RATE_LIMITED\"\n | \"EXPLORE_GLOBAL_LIMIT\"\n | \"CAPTCHA_REQUIRED\"\n | \"CAPTCHA_FAILED\"\n | \"MESSAGE_TOO_LONG\"\n | \"MESSAGE_EMPTY\"\n | \"CONVERSATION_LIMIT\"\n | \"CONVERSATION_BUSY\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"NOT_FOUND\"\n | \"HTTP_429\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\";\n\n// ============================================================================\n// Object types\n// ============================================================================\n\n/** `type ExploreReference` — a cited source page for an answer. */\nexport interface ExploreReference {\n url: string;\n title?: string | null;\n description?: string | null;\n product?: string | null;\n imageUrl?: string | null;\n /** 1-based citation number; the answer text carries a matching `[n]` marker. */\n index?: number | null;\n}\n\n/**\n * `type ExploreCta` — a suggested next step attached to an answer.\n *\n * Named `ExploreCtaLink` in the SDK because `ExploreCta` is taken by the\n * exported nav component (`<ExploreCta variant=\"header\" />`). Same shape,\n * different name; the GraphQL type is unchanged.\n */\nexport interface ExploreCtaLink {\n /** One of {@link ExploreCtaKind}; unknown values render with the neutral style. */\n kind: string;\n label: string;\n url: string;\n product?: string | null;\n}\n\n/** `type ExploreMessage`. `content` is `\"\"` while the turn is PENDING. */\nexport interface ExploreMessage {\n id: string;\n conversationId: string;\n role: ExploreMessageRole;\n status: ExploreMessageStatus;\n /** Final answer, markdown. Empty string until the turn completes. */\n content: string;\n /** Streaming preview while PENDING/RUNNING. */\n partialContent?: string | null;\n /** Human-readable progress lines, e.g. \"Searching vibecontrols…\". */\n activity: string[];\n references: ExploreReference[];\n ctas: ExploreCtaLink[];\n /** Up to three suggested next questions, derived from what the answer covered. */\n followUps?: string[] | null;\n /**\n * False when the corpus could not answer. A grounded answer always cites, so an answer\n * with no source is the honest \"we do not have this\" signal rather than a hedge.\n */\n answered?: boolean | null;\n errorCode?: string | null;\n createdAt: string;\n completedAt?: string | null;\n}\n\n/** `type ExploreConversation`. `token` is the client's only handle. */\nexport interface ExploreConversation {\n id: string;\n token: string;\n productSlug?: string | null;\n turnCount: number;\n createdAt: string;\n}\n\n/** `type ExploreProduct` — one product the harness can answer about. */\nexport interface ExploreProduct {\n slug: string;\n name: string;\n tagline?: string | null;\n website: string;\n}\n\n/** `type ExploreLimits` — server-owned caps the composer enforces locally. */\nexport interface ExploreLimits {\n maxMessageLength: number;\n maxTurnsPerConversation: number;\n messagesPerDay: number;\n historyTurns: number;\n}\n\n/**\n * `type ExploreCatalog` — everything the page needs before the first message.\n *\n * `captchaRequired` + `recaptchaSiteKey` are what turn reCAPTCHA v3 on: it is\n * a backend secret change, and no website redeploy is involved.\n */\nexport interface ExploreCatalog {\n enabled: boolean;\n products: ExploreProduct[];\n examplePrompts: string[];\n welcomeTitle: string;\n welcomeBody: string;\n limits: ExploreLimits;\n captchaRequired: boolean;\n recaptchaSiteKey?: string | null;\n}\n\n/** `input SendExploreMessageInput`. */\nexport interface SendExploreMessageInput {\n /** Omit to start a new conversation. */\n conversationToken?: string;\n /** The site the visitor is on — a soft hint, not a hard filter. */\n productSlug?: string;\n message: string;\n /** Only sent when `catalog.captchaRequired`. */\n recaptchaToken?: string;\n locale?: string;\n pageUrl?: string;\n}\n\n/**\n * `type SendExploreMessageResult`.\n *\n * **`assistantMessage.id` is the id to poll** — it comes back `PENDING`.\n */\nexport interface SendExploreMessageResult {\n conversation: ExploreConversation;\n userMessage: ExploreMessage;\n assistantMessage: ExploreMessage;\n remainingToday?: number | null;\n}\n\n// ============================================================================\n// GraphQL documents\n//\n// Only the fields the UI actually renders are requested — a narrower selection\n// set is cheaper to poll (this runs once every ~1.5s per active visitor) and\n// keeps the contract surface the websites depend on small.\n// ============================================================================\n\n/**\n * Shared selection set for every `ExploreMessage` in this file. Inlined as a\n * template string rather than a GraphQL `fragment` so each document stays a\n * single self-contained operation (the SDK client posts raw strings and has no\n * fragment registry).\n */\nconst EXPLORE_MESSAGE_FIELDS = /* GraphQL */ `\n id\n conversationId\n role\n status\n content\n partialContent\n activity\n references {\n url\n title\n description\n product\n imageUrl\n index\n }\n ctas {\n kind\n label\n url\n product\n }\n followUps\n answered\n errorCode\n createdAt\n completedAt\n`;\n\n/** Loaded once per page. Safe to serve from the SDK's 5-minute query cache. */\nexport const EXPLORE_CATALOG_QUERY = /* GraphQL */ `\n query ExploreCatalog($productSlug: String) {\n exploreCatalog(productSlug: $productSlug) {\n enabled\n products {\n slug\n name\n tagline\n website\n }\n examplePrompts\n welcomeTitle\n welcomeBody\n limits {\n maxMessageLength\n maxTurnsPerConversation\n messagesPerDay\n historyTurns\n }\n captchaRequired\n recaptchaSiteKey\n }\n }\n`;\n\n/**\n * The poll. MUST be issued with `client.query(..., { cache: false })` — the\n * default 5-minute cache would return the first PENDING snapshot forever and\n * the answer would never appear.\n */\nexport const EXPLORE_MESSAGE_QUERY = /* GraphQL */ `\n query ExploreMessage($conversationToken: String!, $id: ID!) {\n exploreMessage(conversationToken: $conversationToken, id: $id) {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n }\n`;\n\n/** Submit half of the submit + poll pair. */\nexport const SEND_EXPLORE_MESSAGE_MUTATION = /* GraphQL */ `\n mutation SendExploreMessage($input: SendExploreMessageInput!) {\n sendExploreMessage(input: $input) {\n conversation {\n id\n token\n productSlug\n turnCount\n createdAt\n }\n userMessage {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n assistantMessage {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n remainingToday\n }\n }\n`;\n\n// ============================================================================\n// Response envelopes (what `client.query`/`client.mutate` resolve `data` to)\n// ============================================================================\n\nexport interface ExploreCatalogQueryData {\n exploreCatalog: ExploreCatalog;\n}\n\nexport interface ExploreMessageQueryData {\n exploreMessage: ExploreMessage | null;\n}\n\nexport interface SendExploreMessageMutationData {\n sendExploreMessage: SendExploreMessageResult;\n}\n\n/**\n * Record that the visitor followed a link the answer offered.\n *\n * Fire-and-forget: the browser is navigating away as this goes out, so the result is never\n * waited on and a failure is never surfaced. The server reports `recorded: false` rather\n * than erroring for anything it cannot attribute.\n */\nexport const RECORD_EXPLORE_CLICK_MUTATION = /* GraphQL */ `\n mutation RecordExploreClick($input: RecordExploreClickInput!) {\n recordExploreClick(input: $input) {\n recorded\n }\n }\n`;\n","import type { WebsiteSwitcherProduct } from \"../components/website-switcher\";\n\n/**\n * Canonical Burdenoff ecosystem product list used by WebsiteSwitcher.\n *\n * Sourced from `~/products/websites/burdenoff-website/src/data/products.ts`.\n * Keep this in sync when products are added, renamed, or moved.\n */\nexport const ECOSYSTEM_PRODUCTS: WebsiteSwitcherProduct[] = [\n {\n slug: \"workspaces\",\n name: \"Workspaces\",\n websiteUrl: \"https://burdenoff.com\",\n },\n {\n slug: \"vibecontrols\",\n name: \"VibeControls\",\n websiteUrl: \"https://vibecontrols.com\",\n },\n {\n slug: \"fluidgrids\",\n name: \"FluidGrids\",\n websiteUrl: \"https://fluidgrids.com\",\n },\n // Botlit ships on botlit.ai — botlit.com does not resolve.\n { slug: \"botlit\", name: \"Botlit\", websiteUrl: \"https://www.botlit.ai\" },\n {\n slug: \"bigconsole\",\n name: \"BigConsole\",\n websiteUrl: \"https://bigconsole.com\",\n },\n {\n slug: \"semanticfed\",\n name: \"SemanticFed\",\n websiteUrl: \"https://semanticfed.com\",\n },\n {\n slug: \"intelwatchtower\",\n name: \"IntelWatchtower\",\n websiteUrl: \"https://intelwatchtower.com\",\n },\n { slug: \"buildmyiq\", name: \"BuildMyIQ\", websiteUrl: \"https://buildmyiq.com\" },\n {\n slug: \"assethandler\",\n name: \"AssetHandler\",\n websiteUrl: \"https://assethandler.com\",\n },\n {\n slug: \"crewfoundry\",\n name: \"CrewFoundry\",\n websiteUrl: \"https://crewfoundry.com\",\n },\n {\n slug: \"planmagnet\",\n name: \"PlanMagnet\",\n websiteUrl: \"https://planmagnet.com\",\n },\n {\n slug: \"eventfullymanaged\",\n name: \"EventfullyManaged\",\n websiteUrl: \"https://eventfullymanaged.com\",\n },\n {\n slug: \"headshotmarketing\",\n name: \"HeadshotMarketing\",\n websiteUrl: \"https://headshotmarketing.com\",\n },\n {\n slug: \"technospam\",\n name: \"TechnoSpam\",\n websiteUrl: \"https://technospam.com\",\n },\n { slug: \"kadaikodi\", name: \"Kadaikodi\", websiteUrl: \"https://kadaikodi.com\" },\n {\n slug: \"movethewheels\",\n name: \"MoveTheWheels\",\n websiteUrl: \"https://movethewheels.com\",\n },\n {\n slug: \"healthybowl\",\n name: \"Healthy Bowl\",\n websiteUrl: \"https://gethealthybowl.com\",\n },\n { slug: \"ggnomad\", name: \"GGNomad\", websiteUrl: \"https://ggnomad.com\" },\n {\n slug: \"timecampus\",\n name: \"TimeCampus\",\n websiteUrl: \"https://timecampus.com\",\n },\n {\n slug: \"manufacturedops\",\n name: \"ManufacturedOps\",\n websiteUrl: \"https://manufacturedops.com\",\n },\n {\n slug: \"theglobalfuel\",\n name: \"TheGlobalFuel\",\n websiteUrl: \"https://theglobalfuel.com\",\n },\n {\n slug: \"housingvista\",\n name: \"HousingVista\",\n websiteUrl: \"https://housingvista.com\",\n },\n {\n slug: \"proserviceworld\",\n name: \"ProServiceWorld\",\n websiteUrl: \"https://proserviceworld.com\",\n },\n {\n slug: \"mybodyshield\",\n name: \"MyBodyShield\",\n websiteUrl: \"https://mybodyshield.com\",\n },\n {\n slug: \"artistrybase\",\n name: \"ArtistryBase\",\n websiteUrl: \"https://artistrybase.com\",\n },\n {\n slug: \"theculturepost\",\n name: \"TheCulturePost\",\n websiteUrl: \"https://theculturepost.com\",\n },\n { slug: \"collabkin\", name: \"CollabKin\", websiteUrl: \"https://collabkin.com\" },\n {\n slug: \"comradecircle\",\n name: \"ComradeCircle\",\n websiteUrl: \"https://comradecircle.com\",\n },\n {\n slug: \"brainyrich\",\n name: \"BrainyRich\",\n websiteUrl: \"https://brainyrich.com\",\n },\n {\n slug: \"cosmicintersection\",\n name: \"CosmicIntersection\",\n websiteUrl: \"https://cosmicintersection.com\",\n },\n {\n slug: \"govcitizenhub\",\n name: \"GovCitizenHub\",\n websiteUrl: \"https://govcitizenhub.com\",\n },\n {\n slug: \"adaptercloud\",\n name: \"AdapterCloud\",\n websiteUrl: \"https://adaptercloud.com\",\n },\n {\n slug: \"subscriberbot\",\n name: \"Subscriber Bot\",\n websiteUrl: \"https://subscriberbot.com\",\n },\n {\n slug: \"hookmovies\",\n name: \"HookMovies\",\n websiteUrl: \"https://hookmovies.com\",\n },\n {\n slug: \"coolandlovely\",\n name: \"CoolAndLovely\",\n websiteUrl: \"https://coolandlovely.com\",\n },\n {\n slug: \"atheletebridge\",\n name: \"AthleteBridge\",\n websiteUrl: \"https://atheletebridge.com\",\n },\n {\n slug: \"labsofscience\",\n name: \"LabsOfScience\",\n websiteUrl: \"https://labsofscience.com\",\n },\n {\n slug: \"ecoimpacthub\",\n name: \"EcoImpactHub\",\n websiteUrl: \"https://ecoimpacthub.com\",\n },\n];\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * useExploreChat — the `/explore` conversation state machine.\n *\n * Implements the client half of CONTRACT.md §1: a **submit + poll** exchange.\n * `sendExploreMessage` returns immediately with a PENDING assistant message;\n * the answer arrives by polling `exploreMessage(conversationToken, id)` roughly\n * every 1.5s until it reports COMPLETED or FAILED. Both gateway hops cap a\n * subgraph call at 20s while a turn takes 5-60s, which is why there is no\n * request that simply waits for the answer.\n *\n * Design rules this hook exists to enforce:\n *\n * 1. **The catalog never gates the first paint.** `catalog` is populated with a\n * static fallback synchronously, so `ExplorePage` can render its `<h1>` on\n * the very first render. The websites' prerender waits for an `h1`; if that\n * heading depended on a network round-trip, 38 static builds would capture a\n * blank page.\n * 2. **Polls bypass the query cache.** `client.query(..., { cache: false })` —\n * the default 5-minute cache would hand every later poll the first PENDING\n * snapshot and the answer would never appear.\n * 3. **Nothing outlives the component.** Unmount and `stop()` both cancel the\n * poll chain through a generation counter, so a late response can never\n * write into an unmounted tree.\n */\n\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useWebSDK } from \"../client/provider\";\nimport {\n EXPLORE_CATALOG_QUERY,\n EXPLORE_MESSAGE_QUERY,\n RECORD_EXPLORE_CLICK_MUTATION,\n SEND_EXPLORE_MESSAGE_MUTATION,\n} from \"../components/explore-types\";\nimport { ECOSYSTEM_PRODUCTS } from \"../data/products\";\nimport { getRecaptchaV3Token } from \"../utils/recaptcha-v3\";\n\nimport type {\n ExploreCatalog,\n ExploreCatalogQueryData,\n ExploreLimits,\n ExploreMessage,\n ExploreMessageQueryData,\n SendExploreMessageInput,\n SendExploreMessageMutationData,\n} from \"../components/explore-types\";\n\n// ============================================================================\n// Public types\n// ============================================================================\n\n/**\n * Where the conversation is right now.\n *\n * - `loading` — catalog request in flight (the fallback catalog is already\n * rendered, so this is a refinement, not a blank screen).\n * - `ready` — idle; the composer accepts input.\n * - `sending` — `sendExploreMessage` in flight.\n * - `streaming` — polling the assistant turn; `activity` is live.\n * - `error` — the last turn failed; `retry()` is meaningful and the\n * composer stays usable.\n * - `limited` — rate limited; the composer is disabled.\n * - `disabled` — `exploreCatalog.enabled === false`.\n */\nexport type ExploreChatPhase =\n | \"loading\"\n | \"ready\"\n | \"sending\"\n | \"streaming\"\n | \"error\"\n | \"limited\"\n | \"disabled\";\n\n/** Coarse bucket the UI switches its banner copy and affordances on. */\nexport type ExploreChatErrorKind =\n | \"rate-limit\"\n | \"captcha\"\n | \"timeout\"\n | \"network\"\n | \"disabled\"\n | \"validation\"\n | \"unknown\";\n\nexport interface ExploreChatError {\n /** UI bucket. */\n kind: ExploreChatErrorKind;\n /** Raw `extensions.code` (or a client-side code such as `TIMEOUT`). */\n code: string;\n /** Human-readable, safe to render. */\n message: string;\n /** Whether re-sending the same message could plausibly succeed. */\n retryable: boolean;\n}\n\nexport interface UseExploreChatOptions {\n /** Slug of the product site this page is on — a soft hint to the harness. */\n productSlug?: string;\n /** Full URL of the page, forwarded as `pageUrl`. */\n pageUrl?: string;\n /** BCP-47 locale, forwarded as `locale`. */\n locale?: string;\n /** Poll cadence in ms. Default 1500 (CONTRACT.md §1). */\n pollIntervalMs?: number;\n /** Give up on a turn after this long. Default 90000 (the edge poll timeout). */\n pollTimeoutMs?: number;\n /**\n * Prompts to offer when `exploreCatalog` supplies none. Resolution order is\n * catalog → this option → {@link DEFAULT_EXPLORE_EXAMPLE_PROMPTS}, so a site\n * can ship product-specific prompts without waiting on the backend and still\n * be overridden centrally once the catalog carries them.\n */\n examplePrompts?: string[];\n /** localStorage key for the ACTIVE conversation. Default `boff.explore.v1`. */\n storageKey?: string;\n /** Persist the conversation across reloads within the tab. Default true. */\n persist?: boolean;\n /** Called with the message text each time a send is accepted locally. */\n onSend?: (message: string) => void;\n}\n\nexport interface UseExploreChatResult {\n phase: ExploreChatPhase;\n /** Never null — starts as the static fallback, upgraded by the server. */\n catalog: ExploreCatalog;\n messages: ExploreMessage[];\n /** Latest progress line of the in-flight turn, or null when idle. */\n activity: string | null;\n /** Messages left today for this visitor, when the server reports it. */\n remainingToday: number | null;\n error: ExploreChatError | null;\n /** Product the visitor pinned the conversation to, or null for \"all\". */\n focusProduct: string | null;\n setFocusProduct: (slug: string | null) => void;\n send: (message: string) => Promise<void>;\n /** Stop polling and keep whatever text has streamed so far. */\n stop: () => void;\n /** Re-send the last message after a failed turn. */\n retry: () => void;\n /** Clear the conversation and the persisted session. */\n reset: () => void;\n /** Past conversations held in THIS browser, newest first. */\n history: ArchivedExploreConversation[];\n /** Reopen a past conversation and continue it. */\n openConversation: (token: string) => void;\n /** Forget one past conversation (local only). */\n deleteConversation: (token: string) => void;\n /** Forget every past conversation held in this browser. */\n clearHistory: () => void;\n /**\n * Record that the visitor followed a link this answer offered. Fire-and-forget — never\n * awaited, never throws, and must never delay the navigation it is reporting on.\n */\n recordClick: (\n messageId: string,\n kind: \"CTA\" | \"REFERENCE\",\n url: string,\n ) => void;\n canSend: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = \"boff.explore.v1\";\n/** Where past conversations live. Derived from the active key so a custom key stays paired. */\nconst HISTORY_SUFFIX = \".history\";\n/**\n * How many past conversations to keep, and how many messages of each. Bounded on purpose:\n * localStorage is a few MB per origin and shared with everything else the site stores, so an\n * unbounded archive would eventually start throwing QuotaExceededError on write.\n */\nconst MAX_ARCHIVED_CONVERSATIONS = 15;\nconst MAX_ARCHIVED_MESSAGES = 20;\nconst DEFAULT_POLL_INTERVAL_MS = 1_500;\n/** Matches `EXPLORE_AGENT_TIMEOUT_MS` (CONTRACT.md §3) — the edge gives up too. */\nconst DEFAULT_POLL_TIMEOUT_MS = 90_000;\n/** Per-poll HTTP timeout. Short: a stuck poll must not stall the chain. */\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n/** The submit hop enqueues a job; generous but well under the gateway's 20s. */\nconst SEND_REQUEST_TIMEOUT_MS = 18_000;\n/** Transient poll failures tolerated before the turn is declared dead. */\nconst MAX_CONSECUTIVE_POLL_FAILURES = 4;\n/** Cap on what goes into localStorage — a conversation must not grow unbounded. */\nconst MAX_PERSISTED_MESSAGES = 40;\n\n/** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */\nexport const FALLBACK_EXPLORE_LIMITS: ExploreLimits = {\n maxMessageLength: 2000,\n maxTurnsPerConversation: 20,\n messagesPerDay: 100,\n historyTurns: 6,\n};\n\n/**\n * Prompts shown when neither the catalog nor the consumer supplies any.\n * Deliberately product-agnostic — this SDK renders on 38 different sites.\n */\nexport const DEFAULT_EXPLORE_EXAMPLE_PROMPTS: string[] = [\n \"What does this product actually do?\",\n \"Which Burdenoff product fits my team?\",\n \"How do I get started, step by step?\",\n \"What does it integrate with?\",\n];\n\nconst FALLBACK_WELCOME_TITLE = \"Ask anything about our products\";\nconst FALLBACK_WELCOME_BODY =\n \"Get straight answers drawn from our product documentation and public pages — with links back to the exact page each answer came from.\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction buildFallbackCatalog(examplePrompts?: string[]): ExploreCatalog {\n return {\n enabled: true,\n products: ECOSYSTEM_PRODUCTS.map((p) => ({\n slug: p.slug,\n name: p.name,\n tagline: null,\n website: p.websiteUrl,\n })),\n examplePrompts: examplePrompts?.length\n ? examplePrompts\n : DEFAULT_EXPLORE_EXAMPLE_PROMPTS,\n welcomeTitle: FALLBACK_WELCOME_TITLE,\n welcomeBody: FALLBACK_WELCOME_BODY,\n limits: FALLBACK_EXPLORE_LIMITS,\n captchaRequired: false,\n recaptchaSiteKey: null,\n };\n}\n\n/**\n * Harden a server catalog against partial/degraded responses so a missing\n * field can never blank the page or produce `maxMessageLength: 0` (which would\n * silently disable the composer).\n */\nfunction normalizeCatalog(\n raw: ExploreCatalog,\n fallback: ExploreCatalog,\n): ExploreCatalog {\n return {\n enabled: raw.enabled !== false,\n products: raw.products?.length ? raw.products : fallback.products,\n examplePrompts: raw.examplePrompts?.length\n ? raw.examplePrompts\n : fallback.examplePrompts,\n welcomeTitle: raw.welcomeTitle || fallback.welcomeTitle,\n welcomeBody: raw.welcomeBody || fallback.welcomeBody,\n limits: {\n maxMessageLength:\n raw.limits?.maxMessageLength || fallback.limits.maxMessageLength,\n maxTurnsPerConversation:\n raw.limits?.maxTurnsPerConversation ||\n fallback.limits.maxTurnsPerConversation,\n messagesPerDay:\n raw.limits?.messagesPerDay || fallback.limits.messagesPerDay,\n historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns,\n },\n captchaRequired: raw.captchaRequired === true,\n recaptchaSiteKey: raw.recaptchaSiteKey ?? null,\n };\n}\n\nconst RATE_LIMIT_CODES = new Set([\n \"RATE_LIMITED\",\n \"HTTP_429\",\n \"EXPLORE_GLOBAL_LIMIT\",\n]);\nconst CAPTCHA_CODES = new Set([\"CAPTCHA_FAILED\", \"CAPTCHA_REQUIRED\"]);\nconst NETWORK_CODES = new Set([\n \"NETWORK_ERROR\",\n \"UPSTREAM_UNAVAILABLE\",\n \"CONVERSATION_BUSY\",\n \"PROVIDER_ERROR\",\n \"QUEUE_FULL\",\n]);\nconst VALIDATION_CODES = new Set([\n \"MESSAGE_TOO_LONG\",\n \"MESSAGE_EMPTY\",\n \"CONVERSATION_LIMIT\",\n \"INVALID_INPUT\",\n]);\n\n/**\n * Map a `extensions.code` (or a client-side transport code) onto the bucket the\n * UI renders. Unknown codes are treated as retryable — a transient backend\n * condition we have not enumerated is far more likely than a permanent one.\n */\nexport function classifyExploreError(\n code: string | null | undefined,\n serverMessage?: string | null,\n): ExploreChatError {\n const c = code ?? \"UNKNOWN\";\n if (RATE_LIMIT_CODES.has(c)) {\n return {\n kind: \"rate-limit\",\n code: c,\n message:\n \"You've reached the message limit for now. Please try again later.\",\n retryable: false,\n };\n }\n if (CAPTCHA_CODES.has(c)) {\n return {\n kind: \"captcha\",\n code: c,\n message:\n \"We couldn't verify that you're human. Please try sending that again.\",\n retryable: true,\n };\n }\n if (c === \"TIMEOUT\" || c === \"TOOL_BUDGET\") {\n return {\n kind: \"timeout\",\n code: c,\n message: \"That answer took too long to come back. Try asking again.\",\n retryable: true,\n };\n }\n if (NETWORK_CODES.has(c)) {\n return {\n kind: \"network\",\n code: c,\n message:\n \"We couldn't reach the assistant just now. Check your connection and try again.\",\n retryable: true,\n };\n }\n if (c === \"EXPLORE_DISABLED\") {\n return {\n kind: \"disabled\",\n code: c,\n message: \"Explore is unavailable at the moment. Please check back soon.\",\n retryable: false,\n };\n }\n if (VALIDATION_CODES.has(c)) {\n return {\n kind: \"validation\",\n code: c,\n message: serverMessage || \"That message couldn't be sent.\",\n retryable: false,\n };\n }\n if (c === \"EMPTY_ANSWER\") {\n return {\n kind: \"unknown\",\n code: c,\n message:\n \"No answer came back for that one. Try rephrasing, or ask something more specific.\",\n retryable: true,\n };\n }\n return {\n kind: \"unknown\",\n code: c,\n message: serverMessage || \"Something went wrong. Please try again.\",\n retryable: true,\n };\n}\n\ninterface PersistedExploreState {\n conversationToken: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n}\n\n/** One past conversation, as shown in the history list and restored on click. */\nexport interface ArchivedExploreConversation {\n token: string;\n /** First thing the visitor asked — the human-readable label for the thread. */\n title: string;\n /** ISO timestamp of the last message in the thread. */\n updatedAt: string;\n messageCount: number;\n focusProduct: string | null;\n messages: ExploreMessage[];\n}\n\nfunction historyKey(key: string): string {\n return `${key}${HISTORY_SUFFIX}`;\n}\n\nfunction readArchive(key: string): ArchivedExploreConversation[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(historyKey(key));\n if (!raw) return [];\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (entry): entry is ArchivedExploreConversation =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as ArchivedExploreConversation).token === \"string\" &&\n Array.isArray((entry as ArchivedExploreConversation).messages),\n );\n } catch {\n return [];\n }\n}\n\nfunction writeArchive(\n key: string,\n entries: ArchivedExploreConversation[],\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (entries.length === 0) {\n window.localStorage.removeItem(historyKey(key));\n return;\n }\n window.localStorage.setItem(historyKey(key), JSON.stringify(entries));\n } catch {\n /* private mode or quota — the archive is a convenience, never load-bearing */\n }\n}\n\n/**\n * Fold the given thread into the archive, newest first.\n *\n * Upsert by token rather than append: the same conversation is archived after every completed\n * turn so an abruptly closed tab still leaves a record, and appending would fill the list with\n * duplicates of one thread.\n */\nfunction upsertArchive(\n key: string,\n thread: {\n token: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n },\n): ArchivedExploreConversation[] {\n if (!thread.token) return readArchive(key);\n const real = thread.messages.filter(\n (m) => m.content.trim() !== \"\" || m.role === \"USER\",\n );\n if (real.length === 0) return readArchive(key);\n\n const firstUser = real.find((m) => m.role === \"USER\");\n const entry: ArchivedExploreConversation = {\n token: thread.token,\n title: (firstUser?.content ?? \"Conversation\").trim().slice(0, 80),\n updatedAt: real[real.length - 1]?.createdAt ?? new Date().toISOString(),\n messageCount: real.length,\n focusProduct: thread.focusProduct,\n messages: real.slice(-MAX_ARCHIVED_MESSAGES),\n };\n\n const rest = readArchive(key).filter((e) => e.token !== entry.token);\n const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);\n writeArchive(key, next);\n return next;\n}\n\nfunction readPersisted(key: string): PersistedExploreState | null {\n // SSR / prerender: there is no localStorage, and reading one during the\n // first client render would desync hydration anyway.\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\") return null;\n const record = parsed as Partial<PersistedExploreState>;\n return {\n conversationToken:\n typeof record.conversationToken === \"string\"\n ? record.conversationToken\n : null,\n messages: Array.isArray(record.messages)\n ? record.messages.slice(-MAX_PERSISTED_MESSAGES)\n : [],\n focusProduct:\n typeof record.focusProduct === \"string\" ? record.focusProduct : null,\n };\n } catch {\n /* corrupt or unavailable storage — start a fresh conversation */\n return null;\n }\n}\n\n/**\n * A turn that never produced any text is worth dropping rather than rendering\n * as an empty bubble — used by `stop()` and by the failure paths.\n */\nfunction visibleText(message: ExploreMessage): string {\n return message.content || message.partialContent || \"\";\n}\n\nfunction countUserTurns(messages: ExploreMessage[]): number {\n return messages.filter((m) => m.role === \"USER\").length;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExploreChat(\n options: UseExploreChatOptions = {},\n): UseExploreChatResult {\n const {\n productSlug,\n pageUrl,\n locale,\n examplePrompts,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,\n storageKey = DEFAULT_STORAGE_KEY,\n persist = true,\n onSend,\n } = options;\n\n const client = useWebSDK();\n\n // The fallback catalog is the initial value AND the merge base for the\n // server response. Keyed on the prompt CONTENT, not the array identity —\n // a consumer passing an inline `examplePrompts={[...]}` literal would\n // otherwise rebuild it every render and re-fire the catalog effect.\n const promptKey = JSON.stringify(examplePrompts ?? []);\n const fallbackCatalog = useMemo(\n () => buildFallbackCatalog(JSON.parse(promptKey) as string[]),\n [promptKey],\n );\n\n const [catalog, setCatalog] = useState<ExploreCatalog>(fallbackCatalog);\n const [messages, setMessages] = useState<ExploreMessage[]>([]);\n const [phase, setPhase] = useState<ExploreChatPhase>(\"loading\");\n const [error, setError] = useState<ExploreChatError | null>(null);\n const [remainingToday, setRemainingToday] = useState<number | null>(null);\n const [focusProduct, setFocusProductState] = useState<string | null>(null);\n const [turnCount, setTurnCount] = useState(0);\n // Mirror of `messages` for callbacks that must not re-create on every message.\n const messagesRef = useRef<ExploreMessage[]>([]);\n const [archive, setArchive] = useState<ArchivedExploreConversation[]>([]);\n\n const [hydrated, setHydrated] = useState(false);\n\n // Refs mirror the state that async callbacks read, so `send`/`poll` never\n // close over a stale value and never need to be re-created mid-flight.\n const mountedRef = useRef(true);\n const pollGenerationRef = useRef(0);\n const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const conversationTokenRef = useRef<string | null>(null);\n const catalogRef = useRef<ExploreCatalog>(fallbackCatalog);\n const turnCountRef = useRef(0);\n const focusProductRef = useRef<string | null>(null);\n const lastSentTextRef = useRef<string | null>(null);\n const inFlightRef = useRef(false);\n\n catalogRef.current = catalog;\n\n const clearPollTimer = useCallback(() => {\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n }, []);\n\n /** Invalidate any running poll chain. Late responses become no-ops. */\n const cancelPolling = useCallback(() => {\n pollGenerationRef.current += 1;\n clearPollTimer();\n }, [clearPollTimer]);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n pollGenerationRef.current += 1;\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n };\n }, []);\n\n // --------------------------------------------------------------------------\n // Hydrate from localStorage (effect, not lazy state, so the FIRST client\n // render matches the prerendered HTML and hydration stays clean).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist) {\n setHydrated(true);\n return;\n }\n setArchive(readArchive(storageKey));\n const stored = readPersisted(storageKey);\n if (stored) {\n conversationTokenRef.current = stored.conversationToken;\n focusProductRef.current = stored.focusProduct;\n // A turn that was still streaming when the tab was closed can never be\n // resumed from here — the poll chain is gone. Land it as-is.\n const settled = stored.messages.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"COMPLETED\", content: text }];\n });\n setMessages(settled);\n setFocusProductState(stored.focusProduct);\n const turns = countUserTurns(settled);\n turnCountRef.current = turns;\n setTurnCount(turns);\n }\n setHydrated(true);\n }, [persist, storageKey]);\n\n // --------------------------------------------------------------------------\n // Persist (after hydration, so the initial empty state never wipes storage).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist || !hydrated || typeof window === \"undefined\") return;\n try {\n const payload: PersistedExploreState = {\n conversationToken: conversationTokenRef.current,\n messages: messages.slice(-MAX_PERSISTED_MESSAGES),\n focusProduct,\n };\n // Nothing worth restoring (fresh page, or just after reset()): drop the\n // key entirely rather than leaving an empty husk behind.\n if (\n !payload.conversationToken &&\n payload.messages.length === 0 &&\n !payload.focusProduct\n ) {\n window.localStorage.removeItem(storageKey);\n return;\n }\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n /* private mode / quota exceeded — persistence is a nicety, not a feature */\n }\n }, [persist, hydrated, storageKey, messages, focusProduct]);\n\n // Mirror messages into a ref for callbacks, and fold a settled thread into the archive.\n // Archiving on every settled turn (not only on reset) is what makes an abruptly closed tab\n // still leave a record the visitor can come back to.\n useEffect(() => {\n messagesRef.current = messages;\n if (!persist || !hydrated) return;\n const settled = messages.some(\n (m) =>\n m.role === \"ASSISTANT\" &&\n (m.status === \"COMPLETED\" || m.status === \"FAILED\"),\n );\n if (!settled) return;\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages,\n focusProduct: focusProductRef.current,\n }),\n );\n }, [messages, persist, hydrated, storageKey]);\n\n // --------------------------------------------------------------------------\n // Catalog. Cached (the default) — it is per-page-load configuration, not a\n // poll. A failure keeps the fallback so the page NEVER renders blank.\n // --------------------------------------------------------------------------\n useEffect(() => {\n let cancelled = false;\n const load = async () => {\n const res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY,\n { productSlug: productSlug ?? null },\n );\n if (cancelled || !mountedRef.current) return;\n\n const raw = res.data?.exploreCatalog;\n if (res.errors?.length || !raw) {\n console.warn(\n \"[WebSDK] exploreCatalog unavailable — using the built-in fallback catalog\",\n res.errors?.[0]?.message,\n );\n setPhase((prev) => (prev === \"loading\" ? \"ready\" : prev));\n return;\n }\n\n const next = normalizeCatalog(raw, fallbackCatalog);\n setCatalog(next);\n catalogRef.current = next;\n setPhase((prev) => {\n if (!next.enabled) return \"disabled\";\n return prev === \"loading\" ? \"ready\" : prev;\n });\n };\n void load();\n return () => {\n cancelled = true;\n };\n }, [client, productSlug, fallbackCatalog]);\n\n // --------------------------------------------------------------------------\n // Poll chain\n // --------------------------------------------------------------------------\n const startPolling = useCallback(\n (conversationToken: string, messageId: string) => {\n pollGenerationRef.current += 1;\n const generation = pollGenerationRef.current;\n const startedAt = Date.now();\n let consecutiveFailures = 0;\n\n const isStale = () =>\n !mountedRef.current || generation !== pollGenerationRef.current;\n\n const finishWithError = (chatError: ExploreChatError) => {\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.id !== messageId) return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"FAILED\", content: text }];\n }),\n );\n setError(chatError);\n setPhase(chatError.kind === \"rate-limit\" ? \"limited\" : \"error\");\n };\n\n const tick = async () => {\n if (isStale()) return;\n\n if (Date.now() - startedAt > pollTimeoutMs) {\n finishWithError(classifyExploreError(\"TIMEOUT\"));\n return;\n }\n\n // `cache: false` is load-bearing — see CONTRACT.md §4.\n const res = await client.query<ExploreMessageQueryData>(\n EXPLORE_MESSAGE_QUERY,\n { conversationToken, id: messageId },\n { cache: false, timeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n if (isStale()) return;\n\n const first = res.errors?.[0];\n if (first) {\n const code =\n typeof first.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first.message);\n // Hard stops: retrying a rate limit or a disabled feature is pointless.\n if (!classified.retryable) {\n finishWithError(classified);\n return;\n }\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classified);\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n const message = res.data?.exploreMessage;\n if (!message) {\n // Can happen briefly right after submit; tolerate a few misses.\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classifyExploreError(\"NOT_FOUND\"));\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n consecutiveFailures = 0;\n // Replace in place so `partialContent` renders as it streams.\n setMessages((prev) =>\n prev.map((m) => (m.id === messageId ? message : m)),\n );\n\n if (message.status === \"COMPLETED\") {\n inFlightRef.current = false;\n setError(null);\n setPhase(\"ready\");\n return;\n }\n if (message.status === \"FAILED\") {\n finishWithError(\n classifyExploreError(message.errorCode ?? \"UPSTREAM_UNAVAILABLE\"),\n );\n return;\n }\n\n setPhase(\"streaming\");\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n };\n\n // First poll after one interval — the turn cannot possibly be done sooner.\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n },\n [client, pollIntervalMs, pollTimeoutMs],\n );\n\n // --------------------------------------------------------------------------\n // send\n // --------------------------------------------------------------------------\n const submit = useCallback(\n async (\n text: string,\n optimisticId: string,\n captchaAttempt: number,\n ): Promise<void> => {\n const activeCatalog = catalogRef.current;\n\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\"[WebSDK] reCAPTCHA v3 token could not be minted\", err);\n // Send without a token and let the backend decide — it owns the\n // policy, and a blocked third-party script must not silently kill\n // the whole feature.\n }\n }\n\n const input: SendExploreMessageInput = {\n message: text,\n ...(conversationTokenRef.current\n ? { conversationToken: conversationTokenRef.current }\n : {}),\n ...(focusProductRef.current || productSlug\n ? { productSlug: focusProductRef.current ?? productSlug }\n : {}),\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(locale ? { locale } : {}),\n ...(pageUrl ? { pageUrl } : {}),\n };\n\n const res = await client.mutate<SendExploreMessageMutationData>(\n SEND_EXPLORE_MESSAGE_MUTATION,\n { input },\n { timeoutMs: SEND_REQUEST_TIMEOUT_MS },\n );\n if (!mountedRef.current) return;\n\n const first = res.errors?.[0];\n const result = res.data?.sendExploreMessage;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first?.message);\n\n // CAPTCHA_FAILED: one silent re-mint + re-send before bothering the\n // visitor. v3 tokens expire in ~2 minutes and are single-use, so a\n // stale one is a routine, self-healing failure.\n if (classified.kind === \"captcha\" && captchaAttempt === 0) {\n await submit(text, optimisticId, 1);\n return;\n }\n\n inFlightRef.current = false;\n setError(classified);\n setPhase(classified.kind === \"rate-limit\" ? \"limited\" : \"error\");\n return;\n }\n\n conversationTokenRef.current = result.conversation.token;\n turnCountRef.current = result.conversation.turnCount;\n setTurnCount(result.conversation.turnCount);\n setRemainingToday(result.remainingToday ?? null);\n\n const userMessage = result.userMessage;\n const assistantMessage = result.assistantMessage;\n\n // Swap the optimistic user bubble for the server's, then append the\n // PENDING assistant turn that the poll chain will fill in. The `some`\n // guard keeps the visitor's words on screen even in the impossible case\n // where the optimistic bubble is already gone.\n setMessages((prev) => {\n const replaced = prev.some((m) => m.id === optimisticId)\n ? prev.map((m) => (m.id === optimisticId ? userMessage : m))\n : [...prev, userMessage];\n return [...replaced, assistantMessage];\n });\n\n if (\n assistantMessage.status === \"COMPLETED\" ||\n assistantMessage.status === \"FAILED\"\n ) {\n inFlightRef.current = false;\n if (assistantMessage.status === \"FAILED\") {\n const classified = classifyExploreError(\n assistantMessage.errorCode ?? \"UPSTREAM_UNAVAILABLE\",\n );\n setError(classified);\n setPhase(\"error\");\n } else {\n setPhase(\"ready\");\n }\n return;\n }\n\n setPhase(\"streaming\");\n startPolling(result.conversation.token, assistantMessage.id);\n },\n [client, locale, pageUrl, productSlug, startPolling],\n );\n\n const send = useCallback(\n async (message: string): Promise<void> => {\n const text = message.trim();\n if (!text) return;\n if (inFlightRef.current) return;\n\n const activeCatalog = catalogRef.current;\n if (!activeCatalog.enabled) {\n setError(classifyExploreError(\"EXPLORE_DISABLED\"));\n setPhase(\"disabled\");\n return;\n }\n if (text.length > activeCatalog.limits.maxMessageLength) {\n setError({\n kind: \"validation\",\n code: \"MESSAGE_TOO_LONG\",\n message: `That message is ${text.length} characters — the limit is ${activeCatalog.limits.maxMessageLength}.`,\n retryable: false,\n });\n return;\n }\n if (\n turnCountRef.current >= activeCatalog.limits.maxTurnsPerConversation\n ) {\n setError({\n kind: \"validation\",\n code: \"CONVERSATION_LIMIT\",\n message: `This conversation has reached its ${activeCatalog.limits.maxTurnsPerConversation}-message limit. Start a new chat to keep going.`,\n retryable: false,\n });\n return;\n }\n\n inFlightRef.current = true;\n lastSentTextRef.current = text;\n setError(null);\n setPhase(\"sending\");\n cancelPolling();\n\n // Optimistic user bubble — the composer clears instantly instead of\n // waiting a network round-trip for the visitor's own words.\n const optimistic: ExploreMessage = {\n id: makeOptimisticId(),\n conversationId: conversationTokenRef.current ?? \"pending\",\n role: \"USER\",\n status: \"COMPLETED\",\n content: text,\n partialContent: null,\n activity: [],\n references: [],\n ctas: [],\n errorCode: null,\n createdAt: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n };\n setMessages((prev) => [...prev, optimistic]);\n turnCountRef.current += 1;\n setTurnCount(turnCountRef.current);\n onSend?.(text);\n\n try {\n await submit(text, optimistic.id, 0);\n } catch (err) {\n if (!mountedRef.current) return;\n console.error(\"[WebSDK] Explore send failed\", err);\n inFlightRef.current = false;\n setError(classifyExploreError(\"NETWORK_ERROR\"));\n setPhase(\"error\");\n }\n },\n [cancelPolling, onSend, submit],\n );\n\n const stop = useCallback(() => {\n cancelPolling();\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n // Nothing streamed yet — drop the placeholder instead of leaving an\n // empty bubble behind.\n if (!text) return [];\n return [\n {\n ...m,\n status: \"COMPLETED\",\n content: text,\n completedAt: new Date().toISOString(),\n },\n ];\n }),\n );\n setPhase((prev) =>\n prev === \"sending\" || prev === \"streaming\" ? \"ready\" : prev,\n );\n }, [cancelPolling]);\n\n const retry = useCallback(() => {\n const text = lastSentTextRef.current;\n if (!text) return;\n cancelPolling();\n inFlightRef.current = false;\n // Drop the failed turn (and the user bubble that produced it) so the retry\n // does not stack a duplicate pair into the transcript.\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last?.role === \"ASSISTANT\" && last.status === \"FAILED\") next.pop();\n const prior = next[next.length - 1];\n if (prior?.role === \"USER\" && prior.content === text) next.pop();\n return next;\n });\n turnCountRef.current = Math.max(0, turnCountRef.current - 1);\n setTurnCount(turnCountRef.current);\n void send(text);\n }, [cancelPolling, send]);\n\n const reset = useCallback(() => {\n // Archive the thread being left behind, so \"New chat\" never destroys history.\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n }),\n );\n cancelPolling();\n inFlightRef.current = false;\n conversationTokenRef.current = null;\n lastSentTextRef.current = null;\n turnCountRef.current = 0;\n setTurnCount(0);\n setMessages([]);\n setError(null);\n setRemainingToday(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n if (typeof window !== \"undefined\") {\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n /* storage unavailable — nothing to clear */\n }\n }\n }, [cancelPolling, storageKey]);\n\n /**\n * Reopen a past conversation. The messages come from the local archive rather than the server:\n * the backend expires a job's state, and a visitor looking at their own history should see it\n * whether or not the server still holds anything. The token is restored too, so the next\n * message continues the SAME server-side conversation.\n */\n const openConversation = useCallback(\n (token: string) => {\n const entry = readArchive(storageKey).find((e) => e.token === token);\n if (!entry) return;\n // Archive whatever is on screen first, or switching away would lose it.\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n });\n cancelPolling();\n inFlightRef.current = false;\n conversationTokenRef.current = entry.token;\n turnCountRef.current = entry.messages.filter(\n (m) => m.role === \"USER\",\n ).length;\n setTurnCount(turnCountRef.current);\n setMessages(entry.messages);\n focusProductRef.current = entry.focusProduct;\n setFocusProductState(entry.focusProduct);\n setError(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n setArchive(readArchive(storageKey));\n },\n [cancelPolling, storageKey],\n );\n\n /** Forget one past conversation. Local only — see the page's storage notice. */\n const deleteConversation = useCallback(\n (token: string) => {\n const next = readArchive(storageKey).filter((e) => e.token !== token);\n writeArchive(storageKey, next);\n setArchive(next);\n },\n [storageKey],\n );\n\n /** Forget every past conversation held in this browser. */\n const clearHistory = useCallback(() => {\n writeArchive(storageKey, []);\n setArchive([]);\n }, [storageKey]);\n\n const setFocusProduct = useCallback((slug: string | null) => {\n focusProductRef.current = slug;\n setFocusProductState(slug);\n }, []);\n\n const activity = useMemo<string | null>(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const m = messages[i];\n if (!m || m.role !== \"ASSISTANT\") continue;\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return null;\n const lines = m.activity ?? [];\n return lines.length ? (lines[lines.length - 1] ?? null) : null;\n }\n return null;\n }, [messages]);\n\n const canSend =\n (phase === \"ready\" || phase === \"error\") &&\n catalog.enabled &&\n turnCount < catalog.limits.maxTurnsPerConversation;\n\n /**\n * Tell the server the visitor followed one of the links this answer offered.\n *\n * Deliberately fire-and-forget and never awaited: the browser is navigating away as this\n * goes out, so anything that blocked on it would delay the click the visitor actually\n * made. Failures are swallowed — analytics must never break navigation.\n */\n const recordClick = useCallback(\n (messageId: string, kind: \"CTA\" | \"REFERENCE\", url: string): void => {\n const token = conversationTokenRef.current;\n if (!token) return;\n try {\n void client\n .mutate(RECORD_EXPLORE_CLICK_MUTATION, {\n input: { conversationToken: token, messageId, kind, url },\n })\n .catch(() => {\n /* the visitor is mid-navigation; there is nothing useful to do here */\n });\n } catch {\n /* client unavailable — same reasoning */\n }\n },\n [client],\n );\n\n return {\n phase,\n catalog,\n messages,\n activity,\n remainingToday,\n error,\n focusProduct,\n setFocusProduct,\n send,\n stop,\n retry,\n reset,\n canSend,\n history: archive,\n openConversation,\n deleteConversation,\n clearHistory,\n recordClick,\n };\n}\n\n/**\n * Client-only id for the optimistic user bubble, swapped for the server's\n * `userMessage.id` as soon as the mutation resolves. The counter only has to\n * make ids unique within a tab, never across one.\n */\nlet optimisticCounter = 0;\n\nfunction makeOptimisticId(): string {\n optimisticCounter += 1;\n return `boff-explore-local-${Date.now()}-${optimisticCounter}`;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Dictation for the explore composer, on the browser's own speech recogniser.\n *\n * Uses the Web Speech API directly — no dependency, no network call of our own, no audio ever\n * leaving the browser through us. Support is genuinely partial (Chrome, Edge and Safari expose\n * it, most commonly behind the `webkit` prefix; Firefox does not implement it at all), so the\n * caller MUST hide the microphone entirely when `supported` is false rather than offering a\n * control that cannot work.\n *\n * Interim results are surfaced separately from final ones so the composer can show speech\n * appearing live while only committing settled text to the draft.\n *\n * ## Mobile\n *\n * Mobile took three separate fixes, each of which looked like the whole problem:\n *\n * 1. **The prompt never appeared.** `recognition.start()` raises the permission prompt on\n * desktop Chrome but on Android Chrome and iOS fires `not-allowed` without showing\n * anything, so a visitor who had never been asked was told to change a browser setting.\n * `getUserMedia` is what actually prompts, so it is primed first.\n * 2. **Granting still failed.** Recognition opens its OWN capture, and starting it in the same\n * tick that the primed stream is being torn down races that teardown. It now waits for the\n * release, and retries once — Android frequently refuses the first attempt after a\n * permission is newly granted and accepts the second.\n * 3. **`continuous` is not honoured on mobile.** Android Chrome ends the session after a\n * single utterance regardless, and asking for continuous mode makes it fail sooner. Mobile\n * therefore runs single-shot and is restarted from `onend` for as long as the visitor is\n * still dictating, which behaves like continuous without fighting the platform.\n */\n\ninterface SpeechRecognitionAlternativeLike {\n transcript: string;\n}\ninterface SpeechRecognitionResultLike {\n readonly isFinal: boolean;\n readonly length: number;\n [index: number]: SpeechRecognitionAlternativeLike;\n}\ninterface SpeechRecognitionEventLike {\n readonly resultIndex: number;\n readonly results: {\n readonly length: number;\n [index: number]: SpeechRecognitionResultLike;\n };\n}\ninterface SpeechRecognitionErrorEventLike {\n readonly error: string;\n}\ninterface SpeechRecognitionLike {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n start: () => void;\n stop: () => void;\n abort: () => void;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n onend: (() => void) | null;\n onstart: (() => void) | null;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionLike;\n\ninterface SpeechWindow {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n}\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === \"undefined\") return null;\n const w = window as unknown as SpeechWindow;\n return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Coarse pointer means a touch device, which is what actually predicts the recogniser's\n * behaviour here — not the screen size, and not a UA string that lies.\n */\nfunction isTouchDevice(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\nconst MIC_DENIED_MESSAGE =\n \"Microphone access was blocked. Allow it in your browser's site settings to dictate.\";\nconst MIC_UNAVAILABLE_MESSAGE =\n \"Dictation isn't available in this browser. You can type instead.\";\n\n/** Let a released capture settle before recognition opens its own. */\nconst RELEASE_SETTLE_MS = 250;\n/** Android often refuses the first start after a fresh grant and accepts the next. */\nconst RETRY_DELAY_MS = 350;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Ask for the microphone the only way that reliably raises a prompt on mobile.\n *\n * `confirmed` reports whether access was actually VERIFIED, which is what separates \"you need\n * to grant this\" from \"your browser cannot do this\" further down.\n *\n * Must be called synchronously from the user gesture that requested dictation — awaiting\n * anything first spends the gesture and the browser then rejects the request outright.\n */\nasync function ensureMicrophoneAccess(): Promise<\n | { ok: true; confirmed: boolean; primed: boolean }\n | { ok: false; message: string }\n> {\n const media =\n typeof navigator === \"undefined\" ? undefined : navigator.mediaDevices;\n // Older/unusual browsers without mediaDevices: fall through and let recognition try. It\n // may well work, and refusing here would remove dictation from browsers that support it.\n if (!media?.getUserMedia)\n return { ok: true, confirmed: false, primed: false };\n\n // `granted` means the prompt would not appear anyway, so skip the extra capture — which\n // also avoids the teardown race entirely on repeat use.\n //\n // A `denied` reading is deliberately NOT trusted to short-circuit. The Permissions API\n // reports `denied` for a prompt the visitor merely dismissed, and its microphone support\n // is uneven across mobile browsers — believing it would recreate the exact bug this\n // function exists to fix, telling someone to change a setting instead of asking them.\n // getUserMedia is the authoritative check, and when access really is denied it rejects\n // immediately without showing anything, so the only cost of asking is a settled promise.\n //\n // `permissions` is absent on Safari and `microphone` is not a valid name everywhere, so\n // every part of this is optional and failure is non-fatal.\n try {\n const status = await navigator.permissions?.query({\n name: \"microphone\" as PermissionName,\n });\n if (status?.state === \"granted\")\n return { ok: true, confirmed: true, primed: false };\n } catch {\n /* permissions API unavailable or the name is unsupported — prompt below instead */\n }\n\n try {\n const stream = await media.getUserMedia({ audio: true });\n // Release immediately: this capture existed only to raise the prompt, and leaving it\n // open would show a recording indicator for the whole session — and on mobile would\n // occupy the very microphone recognition is about to ask for.\n for (const track of stream.getTracks()) track.stop();\n return { ok: true, confirmed: true, primed: true };\n } catch (error) {\n const name =\n typeof error === \"object\" && error !== null && \"name\" in error\n ? String((error as { name: unknown }).name)\n : \"\";\n if (name === \"NotAllowedError\" || name === \"SecurityError\") {\n return { ok: false, message: MIC_DENIED_MESSAGE };\n }\n if (name === \"NotFoundError\" || name === \"DevicesNotFoundError\") {\n return { ok: false, message: \"No microphone was found.\" };\n }\n return {\n ok: false,\n message: \"Dictation could not start. You can type instead.\",\n };\n }\n}\n\n/** Messages a visitor can act on. `not-allowed` is the one that needs real explanation. */\nfunction describeError(code: string): string {\n switch (code) {\n case \"not-allowed\":\n case \"service-not-allowed\":\n return MIC_DENIED_MESSAGE;\n case \"no-speech\":\n return \"I didn't catch anything — try again a little closer to the mic.\";\n case \"audio-capture\":\n return \"No microphone was found.\";\n case \"network\":\n return \"Speech recognition needs a network connection.\";\n case \"aborted\":\n return \"\";\n default:\n return \"Dictation stopped unexpectedly. You can type instead.\";\n }\n}\n\nexport interface UseSpeechInputOptions {\n /** Receives settled text as it is recognised. Append it to the draft. */\n onFinalTranscript: (text: string) => void;\n /** BCP-47 tag. Defaults to the browser's language. */\n lang?: string;\n /** Called when the recogniser reports a problem worth showing. */\n onError?: (message: string) => void;\n}\n\nexport interface UseSpeechInputResult {\n /** False when the browser has no speech recogniser — hide the control entirely. */\n supported: boolean;\n listening: boolean;\n /** Words recognised but not yet settled; render as a live hint, do not store. */\n interim: string;\n error: string | null;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n}\n\nexport function useSpeechInput({\n onFinalTranscript,\n lang,\n onError,\n}: UseSpeechInputOptions): UseSpeechInputResult {\n const [supported] = useState(() => getRecognitionCtor() !== null);\n const [listening, setListening] = useState(false);\n const [interim, setInterim] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const recognitionRef = useRef<SpeechRecognitionLike | null>(null);\n /**\n * Bumped on every start()/stop(). A permission prompt, a settle delay or a retry resolving\n * after the visitor moved on must not open a microphone behind them.\n */\n const startTokenRef = useRef(0);\n /**\n * True only when the microphone was actually VERIFIED for this attempt — permission\n * reported granted, or getUserMedia succeeded. Stays false on browsers with no\n * mediaDevices, where nothing was checked and a recogniser `not-allowed` may still be a\n * real permission problem.\n */\n const micConfirmedRef = useRef(false);\n /** The visitor's intent, as opposed to whether a session happens to be open right now. */\n const wantsListeningRef = useRef(false);\n /** One retry per start(), for the Android \"refuses the first attempt\" case. */\n const retriedRef = useRef(false);\n\n // Held in refs so the recogniser's long-lived handlers always call the latest closures\n // without tearing down and re-creating the recogniser on every render.\n const finalRef = useRef(onFinalTranscript);\n const errorRef = useRef(onError);\n finalRef.current = onFinalTranscript;\n errorRef.current = onError;\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const stop = useCallback(() => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n /** Open a recogniser session. Separate from start() so a retry can reuse it. */\n const openSession = useCallback((token: number) => {\n const Ctor = getRecognitionCtor();\n if (!Ctor || token !== startTokenRef.current) return;\n\n const recognition = new Ctor();\n recognition.lang =\n langRef.current ??\n (typeof navigator === \"undefined\"\n ? \"en-US\"\n : navigator.language || \"en-US\");\n // Continuous mode is a desktop-only affordance. Android Chrome ends the session after a\n // single utterance whatever this says, and asking for continuous makes it fail sooner —\n // mobile is restarted from `onend` instead, which behaves the same to the visitor.\n recognition.continuous = !isTouchDevice();\n recognition.interimResults = true;\n recognition.maxAlternatives = 1;\n\n recognition.onstart = () => {\n if (token !== startTokenRef.current) return;\n // NOTE: the retry budget is deliberately NOT reset here. It belongs to the visitor's\n // press, not to the session — a browser that fires onstart and then immediately\n // errors would otherwise retry forever.\n setError(null);\n setListening(true);\n };\n\n recognition.onresult = (event) => {\n if (token !== startTokenRef.current) return;\n let settled = \"\";\n let pending = \"\";\n for (let i = event.resultIndex; i < event.results.length; i += 1) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? \"\";\n if (result.isFinal) settled += text;\n else pending += text;\n }\n setInterim(pending);\n if (settled.trim() !== \"\") finalRef.current(settled);\n };\n\n recognition.onerror = (event) => {\n if (token !== startTokenRef.current) return;\n\n // Android commonly refuses the FIRST start after a permission is newly granted and\n // accepts the next one. Retry once, silently, before telling the visitor anything —\n // an error message they can do nothing about is worse than a short pause.\n if (\n (event.error === \"not-allowed\" ||\n event.error === \"service-not-allowed\") &&\n micConfirmedRef.current &&\n !retriedRef.current\n ) {\n retriedRef.current = true;\n void sleep(RETRY_DELAY_MS).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n\n // The microphone was verified moments ago, so a `not-allowed` that survived the retry\n // is the SPEECH SERVICE refusing, not a permission the visitor can grant. Sending them\n // to a site setting would point at something that cannot help.\n const message =\n micConfirmedRef.current &&\n (event.error === \"not-allowed\" || event.error === \"service-not-allowed\")\n ? MIC_UNAVAILABLE_MESSAGE\n : describeError(event.error);\n\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n if (message !== \"\") {\n setError(message);\n errorRef.current?.(message);\n }\n };\n\n recognition.onend = () => {\n if (token !== startTokenRef.current) return;\n setInterim(\"\");\n // Single-shot mobile sessions end after each utterance. While the visitor still has\n // dictation switched on, reopen so it behaves like continuous mode.\n if (wantsListeningRef.current && isTouchDevice()) {\n void sleep(120).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n setListening(false);\n };\n\n recognitionRef.current = recognition;\n try {\n recognition.start();\n } catch {\n // Chrome throws InvalidStateError if start() races a session that is still closing.\n // The onend handler above will not fire for a session that never began, so settle here.\n wantsListeningRef.current = false;\n setListening(false);\n }\n }, []);\n\n // openSession refers to itself from its own handlers (retry, mobile restart), which a plain\n // const cannot do inside useCallback.\n const openSessionRef = useRef<((token: number) => void) | null>(null);\n openSessionRef.current = openSession;\n\n const start = useCallback(() => {\n if (!getRecognitionCtor()) return;\n\n startTokenRef.current += 1;\n const token = startTokenRef.current;\n wantsListeningRef.current = true;\n retriedRef.current = false;\n micConfirmedRef.current = false;\n\n // Show the pressed state straight away: the permission prompt can sit on screen for a\n // while on mobile, and a mic button that looks inert invites a second tap.\n setError(null);\n setListening(true);\n\n void ensureMicrophoneAccess().then(async (access) => {\n // A stop() or a newer start() landed while the prompt was open — abandon this attempt.\n if (token !== startTokenRef.current) return;\n\n if (!access.ok) {\n wantsListeningRef.current = false;\n setListening(false);\n setError(access.message);\n errorRef.current?.(access.message);\n return;\n }\n\n micConfirmedRef.current = access.confirmed;\n\n // Recognition opens its own capture. Starting in the same tick that the primed stream\n // is being torn down races that teardown and is refused — this is what made \"I granted\n // it and it still says blocked\" happen on mobile.\n if (access.primed) {\n await sleep(RELEASE_SETTLE_MS);\n if (token !== startTokenRef.current) return;\n }\n\n openSessionRef.current?.(token);\n });\n }, []);\n\n const toggle = useCallback(() => {\n if (listening) stop();\n else start();\n }, [listening, start, stop]);\n\n // Never leave the microphone open behind a closed page.\n useEffect(\n () => () => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n const recognition = recognitionRef.current;\n if (!recognition) return;\n recognition.onresult = null;\n recognition.onerror = null;\n recognition.onend = null;\n recognition.onstart = null;\n try {\n recognition.abort();\n } catch {\n /* nothing to abort */\n }\n },\n [],\n );\n\n return { supported, listening, interim, error, start, stop, toggle };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/security.ts","../../src/client/graphql-client.ts","../../src/client/provider.tsx","../../src/components/explore-types.ts","../../src/data/products.ts","../../src/utils/recaptcha-v3.ts","../../src/hooks/use-explore-chat.ts","../../src/hooks/use-speech-input.ts"],"names":["useMemo","useState","useRef","useCallback","useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["const LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\"]);\nconst RESERVED_HEADERS = new Set([\n \"authorization\",\n \"cookie\",\n \"x-actor-id\",\n \"x-actor-type\",\n \"x-consent-granted-by\",\n \"x-consent-scope\",\n \"x-consent-granted-at\",\n \"x-consent-expires-at\",\n]);\n\nexport function validateGatewayUrl(value: string): string {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Gateway URL must be a valid absolute URL\");\n }\n\n if (url.protocol === \"https:\") {\n return url.toString();\n }\n\n if (\n url.protocol === \"http:\" &&\n LOOPBACK_HOSTS.has(url.hostname.toLowerCase())\n ) {\n return url.toString();\n }\n\n throw new Error(\"Gateway URL must use HTTPS unless it targets localhost\");\n}\n\nexport function sanitizeHeaders(\n headers?: Record<string, string>,\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([key]) => !RESERVED_HEADERS.has(key.toLowerCase()),\n ),\n );\n}\n\n/**\n * Hostnames whose Cloudflare Access application gates the GraphQL gateway.\n *\n * Only the alpha gateways are gated; the production gateways are public, so a token is never\n * attached there even if one is configured.\n */\nconst CF_ACCESS_GATED_HOSTS = new Set([\n \"alphagraphql.burdenoff.com\",\n \"alphagraphqlworkspaces.burdenoff.com\",\n]);\n\n/**\n * Service-token headers for a gated gateway, or nothing.\n *\n * Returns an empty object unless the target really is a gated host AND both halves of the token\n * are present — a half-configured token would send a malformed credential to every request.\n */\nexport function cfAccessHeaders(\n gatewayUrl: string,\n cfAccess?: { clientId?: string; clientSecret?: string },\n): Record<string, string> {\n const clientId = cfAccess?.clientId?.trim();\n const clientSecret = cfAccess?.clientSecret?.trim();\n if (!clientId || !clientSecret) return {};\n\n let host: string;\n try {\n host = new URL(gatewayUrl).hostname.toLowerCase();\n } catch {\n return {};\n }\n if (!CF_ACCESS_GATED_HOSTS.has(host)) return {};\n\n return {\n \"CF-Access-Client-Id\": clientId,\n \"CF-Access-Client-Secret\": clientSecret,\n };\n}\n","/**\n * Lightweight GraphQL client for the Burdenoff Web SDK.\n * Uses native fetch - zero external dependencies.\n * All calls are unauthenticated (public gateway operations only).\n */\n\nimport {\n cfAccessHeaders,\n sanitizeHeaders,\n validateGatewayUrl,\n} from \"./security\";\n\nexport interface WebSDKClientConfig {\n /** Global public gateway URL (e.g. \"https://api.burdenoff.com/global/graphql\") */\n gatewayUrl: string;\n /** Platform product ID for scoping operations */\n productId: string;\n /** Product slug (used for public product queries) */\n productSlug?: string;\n /** reCAPTCHA site key (if not fetched from product config) */\n recaptchaSiteKey?: string;\n /** Rybbit analytics site ID */\n rybbitSiteId?: string;\n /** Custom headers to include in all requests */\n headers?: Record<string, string>;\n /**\n * Cloudflare Access service token, for the ALPHA gateway hosts only.\n *\n * `alphagraphql.burdenoff.com` sits behind a Cloudflare Access application, so an\n * unauthenticated browser XHR is answered with a 302 to the Access login on a different\n * origin — which the browser reports as an opaque CORS failure rather than a 401. Attaching\n * the service-token headers is how every app shell already passes that gate (fe-libs\n * `installGatewayFetchRewrite`); the website SDK previously had no equivalent, so contact,\n * newsletter, waitlist and explore all failed on alpha.\n *\n * Vite only inlines `VITE_*` into APP source, never into a bundled library, so the host app\n * must read `import.meta.env` and pass the values in. Production gateways are not gated and\n * receive no headers.\n */\n cfAccess?: { clientId?: string; clientSecret?: string };\n /**\n * Per-request timeout in ms. Kept below the gateway's operation timeout so a\n * stalled request surfaces as an error the UI can render, instead of leaving\n * a page stuck on loading skeletons forever. Default 12000.\n */\n timeoutMs?: number;\n /**\n * Extra attempts for transient failures (timeout / network / 5xx / 429) on\n * QUERIES ONLY. Mutations are never retried — a retried contact-form or\n * waitlist submit would double-submit. Default 1 (2 attempts total).\n */\n maxRetries?: number;\n}\n\n/**\n * Per-call overrides for {@link WebSDKClient.query}.\n *\n * The defaults (5-minute response cache + in-flight deduplication) are right\n * for the read-once content queries most SDK components make, and wrong for a\n * poll loop: the second poll of the same `(query, variables)` pair would be\n * served straight from the cache and the UI would freeze on the first\n * response forever. Pass `{ cache: false }` for anything polled.\n */\nexport interface WebSDKQueryOptions {\n /**\n * Use the response cache and in-flight deduplication. Default `true`.\n * `false` skips the cache read, the dedupe map AND the cache write, so the\n * call always hits the network and never poisons a later cached read.\n */\n cache?: boolean;\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\n/** Per-call overrides for {@link WebSDKClient.mutate}. */\nexport interface WebSDKMutateOptions {\n /** Override the client-wide request timeout for this call only. */\n timeoutMs?: number;\n}\n\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data?: T;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: Array<string | number>;\n extensions?: Record<string, unknown>;\n }>;\n}\n\nexport class WebSDKClient {\n private config: WebSDKClientConfig;\n private queryCache = new Map<\n string,\n { data: GraphQLResponse<unknown>; ts: number }\n >();\n private inflight = new Map<string, Promise<GraphQLResponse<unknown>>>();\n private static CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n private static MAX_CACHE_ENTRIES = 100;\n private static DEFAULT_TIMEOUT_MS = 12_000;\n private static DEFAULT_MAX_RETRIES = 1;\n private static RETRY_BASE_DELAY_MS = 400;\n\n constructor(config: WebSDKClientConfig) {\n this.config = {\n ...config,\n gatewayUrl: validateGatewayUrl(config.gatewayUrl),\n headers: sanitizeHeaders(config.headers),\n };\n }\n\n getConfig(): WebSDKClientConfig {\n return this.config;\n }\n\n /**\n * Execute a GraphQL query (with deduplication and caching).\n *\n * Pass `{ cache: false }` to bypass the cache entirely — required for poll\n * loops, where every tick must reach the network.\n */\n async query<T = Record<string, unknown>>(\n query: string,\n variables?: Record<string, unknown>,\n options?: WebSDKQueryOptions,\n ): Promise<GraphQLResponse<T>> {\n // Uncached path: no cache read, no in-flight dedupe, no cache write.\n // Deliberately bypasses the dedupe map too — two identical polls issued a\n // few hundred ms apart must both hit the network, otherwise the second one\n // resolves with the first one's (already stale) snapshot.\n if (options?.cache === false) {\n return this.request<T>(query, variables, true, options.timeoutMs);\n }\n\n const cacheKey = JSON.stringify({ query, variables });\n\n // Return cached response if still valid, evict if expired\n const cached = this.queryCache.get(cacheKey);\n if (cached) {\n if (Date.now() - cached.ts < WebSDKClient.CACHE_TTL) {\n return cached.data as GraphQLResponse<T>;\n }\n this.queryCache.delete(cacheKey);\n }\n\n // Deduplicate: if same query is already in-flight, reuse the promise\n const existing = this.inflight.get(cacheKey);\n if (existing) {\n return existing as Promise<GraphQLResponse<T>>;\n }\n\n const promise = this.request<T>(query, variables, true, options?.timeoutMs)\n .then((result) => {\n // Cache successful responses only\n if (result.data && !result.errors?.length) {\n if (this.queryCache.size >= WebSDKClient.MAX_CACHE_ENTRIES) {\n const oldestEntry = this.queryCache.keys().next().value;\n if (oldestEntry) {\n this.queryCache.delete(oldestEntry);\n }\n }\n this.queryCache.set(cacheKey, { data: result, ts: Date.now() });\n }\n return result;\n })\n .finally(() => {\n this.inflight.delete(cacheKey);\n });\n\n this.inflight.set(cacheKey, promise);\n return promise;\n }\n\n /**\n * Execute a GraphQL mutation\n */\n async mutate<T = Record<string, unknown>>(\n mutation: string,\n variables?: Record<string, unknown>,\n options?: WebSDKMutateOptions,\n ): Promise<GraphQLResponse<T>> {\n // retry=false: a retried mutation could double-submit (contact form,\n // waitlist signup, order). Only the timeout applies here.\n return this.request<T>(mutation, variables, false, options?.timeoutMs);\n }\n\n /** HTTP statuses worth another attempt — transient server/edge conditions. */\n private static isRetriableStatus(status: number): boolean {\n return status === 429 || status === 408 || (status >= 500 && status < 600);\n }\n\n private static sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Perform the HTTP call with a hard timeout. Every outcome resolves to a\n * GraphQLResponse — callers never hang, so a UI's `loading` state always\n * settles into data or a renderable error.\n */\n private async attempt<T>(\n query: string,\n variables: Record<string, unknown> | undefined,\n timeoutMs: number,\n ): Promise<{ res: GraphQLResponse<T>; retriable: boolean }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(this.config.gatewayUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-product-id\": this.config.productId,\n ...this.config.headers,\n ...cfAccessHeaders(this.config.gatewayUrl, this.config.cfAccess),\n },\n body: JSON.stringify({ query, variables }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n console.error(\n \"[WebSDK] GraphQL request failed\",\n response.status,\n response.statusText,\n );\n return {\n res: {\n errors: [\n {\n message: `HTTP ${response.status}: ${response.statusText}`,\n extensions: { code: `HTTP_${response.status}` },\n },\n ],\n },\n retriable: WebSDKClient.isRetriableStatus(response.status),\n };\n }\n\n return {\n res: (await response.json()) as GraphQLResponse<T>,\n retriable: false,\n };\n } catch (error) {\n const aborted =\n error instanceof Error &&\n (error.name === \"AbortError\" || controller.signal.aborted);\n const message = aborted\n ? `Request timed out after ${timeoutMs}ms`\n : error instanceof Error\n ? error.message\n : \"Network error\";\n console.error(\"[WebSDK] Network error\", message);\n return {\n res: {\n errors: [\n {\n message,\n extensions: { code: aborted ? \"TIMEOUT\" : \"NETWORK_ERROR\" },\n },\n ],\n },\n // Transport-level failures are worth one more try; a genuine outage\n // just fails twice quickly and still renders an error state.\n retriable: true,\n };\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async request<T>(\n query: string,\n variables?: Record<string, unknown>,\n retry = true,\n timeoutOverrideMs?: number,\n ): Promise<GraphQLResponse<T>> {\n const timeoutMs =\n timeoutOverrideMs ??\n this.config.timeoutMs ??\n WebSDKClient.DEFAULT_TIMEOUT_MS;\n const maxRetries = retry\n ? (this.config.maxRetries ?? WebSDKClient.DEFAULT_MAX_RETRIES)\n : 0;\n\n let last: GraphQLResponse<T> | undefined;\n for (let i = 0; i <= maxRetries; i++) {\n const { res, retriable } = await this.attempt<T>(\n query,\n variables,\n timeoutMs,\n );\n if (!retriable || i === maxRetries) return res;\n last = res;\n // Small backoff with jitter so a burst of clients doesn't retry in lockstep.\n await WebSDKClient.sleep(\n WebSDKClient.RETRY_BASE_DELAY_MS * (i + 1) + Math.random() * 200,\n );\n }\n return last as GraphQLResponse<T>;\n }\n}\n","/**\n * React context provider for the Web SDK client.\n * Wraps the application with WebSDKClient configuration.\n */\n\"use client\";\n\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport { resolveGatewayUrl } from \"./gateway-resolver\";\nimport { WebSDKClient, type WebSDKClientConfig } from \"./graphql-client\";\n\nconst WebSDKContext = createContext<WebSDKClient | null>(null);\n\nexport interface WebSDKProviderProps {\n /** SDK client configuration */\n config: WebSDKClientConfig;\n /** Child components */\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the WebSDKClient available to all child components.\n *\n * @example\n * ```tsx\n * <WebSDKProvider config={{\n * gatewayUrl: \"https://api.burdenoff.com/global/graphql\",\n * productId: \"your-product-id\",\n * productSlug: \"your-product\",\n * }}>\n * <App />\n * </WebSDKProvider>\n * ```\n */\nexport function WebSDKProvider({ config, children }: WebSDKProviderProps) {\n const client = useMemo(() => {\n const resolvedConfig = {\n ...config,\n gatewayUrl: resolveGatewayUrl(config.gatewayUrl),\n };\n return new WebSDKClient(resolvedConfig);\n }, [config]);\n\n return (\n <WebSDKContext.Provider value={client}>{children}</WebSDKContext.Provider>\n );\n}\n\n/**\n * Hook to access the WebSDKClient instance.\n * Must be used within a WebSDKProvider.\n */\nexport function useWebSDK(): WebSDKClient {\n const client = useContext(WebSDKContext);\n if (!client) {\n throw new Error(\"useWebSDK must be used within a WebSDKProvider\");\n }\n return client;\n}\n\n/**\n * Hook to access the SDK configuration.\n * Useful for components that need config values like productId, recaptchaSiteKey, etc.\n */\nexport function useWebSDKConfig(): WebSDKClientConfig {\n const client = useWebSDK();\n return client.getConfig();\n}\n","/**\n * Explore chat — TypeScript mirror of the public `/explore` GraphQL contract.\n *\n * Canonical source: `~/products/dev/platform/context/explore/CONTRACT.md` §1\n * (global-support-svc, served through the global PUBLIC gateway with\n * `@rbac(public: true, scopeType: \"global\")`).\n *\n * Nothing in this file may drift from that document. If a shape here looks\n * wrong, fix CONTRACT.md first and tell the backend workstreams — never patch\n * it locally.\n *\n * Nullability note: the contract marks `title`, `description`, `product`,\n * `imageUrl`, `partialContent`, `errorCode`, `completedAt`, `productSlug`,\n * `recaptchaSiteKey` and `remainingToday` as nullable, so every one of them is\n * `?: T | null` here — a GraphQL `null` and an omitted selection both have to\n * be representable.\n */\n\n// ============================================================================\n// Enums (string unions — the wire format is the enum name)\n// ============================================================================\n\nexport type ExploreMessageRole = \"USER\" | \"ASSISTANT\";\n\nexport type ExploreMessageStatus =\n \"PENDING\" | \"RUNNING\" | \"COMPLETED\" | \"FAILED\";\n\n/**\n * The `ExploreCta.kind` values enumerated in CONTRACT.md §1.\n *\n * `ExploreCtaLink.kind` is deliberately typed `string`, not this union: the\n * field is `String!` on the wire, and a kind added server-side must render\n * (falling back to the neutral CTA style) rather than break the build of 38\n * websites. Use this union when you are *producing* a kind.\n */\nexport type ExploreCtaKind =\n | \"CONTACT\"\n | \"PARTNERS\"\n | \"PRICING\"\n | \"SERVICES\"\n | \"WAITLIST\"\n | \"STORE\"\n | \"APP\"\n | \"DOCS\"\n | \"OTHER\";\n\n/**\n * Error codes surfaced through `extensions.code`. `HTTP_429` is what the\n * gateway emits when it rate-limits at the edge; the SDK client also produces\n * `TIMEOUT` / `NETWORK_ERROR` for transport failures.\n */\nexport type ExploreErrorCode =\n | \"EXPLORE_DISABLED\"\n | \"RATE_LIMITED\"\n | \"EXPLORE_GLOBAL_LIMIT\"\n | \"CAPTCHA_REQUIRED\"\n | \"CAPTCHA_FAILED\"\n | \"MESSAGE_TOO_LONG\"\n | \"MESSAGE_EMPTY\"\n | \"CONVERSATION_LIMIT\"\n | \"CONVERSATION_BUSY\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"NOT_FOUND\"\n | \"HTTP_429\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\";\n\n// ============================================================================\n// Object types\n// ============================================================================\n\n/** `type ExploreReference` — a cited source page for an answer. */\nexport interface ExploreReference {\n url: string;\n title?: string | null;\n description?: string | null;\n product?: string | null;\n imageUrl?: string | null;\n /** 1-based citation number; the answer text carries a matching `[n]` marker. */\n index?: number | null;\n}\n\n/**\n * `type ExploreCta` — a suggested next step attached to an answer.\n *\n * Named `ExploreCtaLink` in the SDK because `ExploreCta` is taken by the\n * exported nav component (`<ExploreCta variant=\"header\" />`). Same shape,\n * different name; the GraphQL type is unchanged.\n */\nexport interface ExploreCtaLink {\n /** One of {@link ExploreCtaKind}; unknown values render with the neutral style. */\n kind: string;\n label: string;\n url: string;\n product?: string | null;\n}\n\n/** `type ExploreMessage`. `content` is `\"\"` while the turn is PENDING. */\nexport interface ExploreMessage {\n id: string;\n conversationId: string;\n role: ExploreMessageRole;\n status: ExploreMessageStatus;\n /** Final answer, markdown. Empty string until the turn completes. */\n content: string;\n /** Streaming preview while PENDING/RUNNING. */\n partialContent?: string | null;\n /** Human-readable progress lines, e.g. \"Searching vibecontrols…\". */\n activity: string[];\n references: ExploreReference[];\n ctas: ExploreCtaLink[];\n /** Up to three suggested next questions, derived from what the answer covered. */\n followUps?: string[] | null;\n /**\n * False when the corpus could not answer. A grounded answer always cites, so an answer\n * with no source is the honest \"we do not have this\" signal rather than a hedge.\n */\n answered?: boolean | null;\n errorCode?: string | null;\n createdAt: string;\n completedAt?: string | null;\n}\n\n/** `type ExploreConversation`. `token` is the client's only handle. */\nexport interface ExploreConversation {\n id: string;\n token: string;\n productSlug?: string | null;\n turnCount: number;\n createdAt: string;\n}\n\n/** `type ExploreProduct` — one product the harness can answer about. */\nexport interface ExploreProduct {\n slug: string;\n name: string;\n tagline?: string | null;\n website: string;\n}\n\n/** `type ExploreLimits` — server-owned caps the composer enforces locally. */\nexport interface ExploreLimits {\n maxMessageLength: number;\n maxTurnsPerConversation: number;\n messagesPerDay: number;\n historyTurns: number;\n}\n\n/**\n * `type ExploreCatalog` — everything the page needs before the first message.\n *\n * `captchaRequired` + `recaptchaSiteKey` are what turn reCAPTCHA v3 on: it is\n * a backend secret change, and no website redeploy is involved.\n */\nexport interface ExploreCatalog {\n enabled: boolean;\n products: ExploreProduct[];\n examplePrompts: string[];\n welcomeTitle: string;\n welcomeBody: string;\n limits: ExploreLimits;\n captchaRequired: boolean;\n recaptchaSiteKey?: string | null;\n}\n\n/** `input SendExploreMessageInput`. */\nexport interface SendExploreMessageInput {\n /** Omit to start a new conversation. */\n conversationToken?: string;\n /** The site the visitor is on — a soft hint, not a hard filter. */\n productSlug?: string;\n message: string;\n /** Only sent when `catalog.captchaRequired`. */\n recaptchaToken?: string;\n locale?: string;\n pageUrl?: string;\n}\n\n/**\n * `type SendExploreMessageResult`.\n *\n * **`assistantMessage.id` is the id to poll** — it comes back `PENDING`.\n */\nexport interface SendExploreMessageResult {\n conversation: ExploreConversation;\n userMessage: ExploreMessage;\n assistantMessage: ExploreMessage;\n remainingToday?: number | null;\n}\n\n// ============================================================================\n// GraphQL documents\n//\n// Only the fields the UI actually renders are requested — a narrower selection\n// set is cheaper to poll (this runs once every ~1.5s per active visitor) and\n// keeps the contract surface the websites depend on small.\n// ============================================================================\n\n/**\n * Shared selection set for every `ExploreMessage` in this file. Inlined as a\n * template string rather than a GraphQL `fragment` so each document stays a\n * single self-contained operation (the SDK client posts raw strings and has no\n * fragment registry).\n */\nconst EXPLORE_MESSAGE_FIELDS = /* GraphQL */ `\n id\n conversationId\n role\n status\n content\n partialContent\n activity\n references {\n url\n title\n description\n product\n imageUrl\n index\n }\n ctas {\n kind\n label\n url\n product\n }\n followUps\n answered\n errorCode\n createdAt\n completedAt\n`;\n\n/** Loaded once per page. Safe to serve from the SDK's 5-minute query cache. */\nexport const EXPLORE_CATALOG_QUERY = /* GraphQL */ `\n query ExploreCatalog($productSlug: String) {\n exploreCatalog(productSlug: $productSlug) {\n enabled\n products {\n slug\n name\n tagline\n website\n }\n examplePrompts\n welcomeTitle\n welcomeBody\n limits {\n maxMessageLength\n maxTurnsPerConversation\n messagesPerDay\n historyTurns\n }\n captchaRequired\n recaptchaSiteKey\n }\n }\n`;\n\n/**\n * The poll. MUST be issued with `client.query(..., { cache: false })` — the\n * default 5-minute cache would return the first PENDING snapshot forever and\n * the answer would never appear.\n */\nexport const EXPLORE_MESSAGE_QUERY = /* GraphQL */ `\n query ExploreMessage($conversationToken: String!, $id: ID!) {\n exploreMessage(conversationToken: $conversationToken, id: $id) {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n }\n`;\n\n/** Submit half of the submit + poll pair. */\nexport const SEND_EXPLORE_MESSAGE_MUTATION = /* GraphQL */ `\n mutation SendExploreMessage($input: SendExploreMessageInput!) {\n sendExploreMessage(input: $input) {\n conversation {\n id\n token\n productSlug\n turnCount\n createdAt\n }\n userMessage {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n assistantMessage {\n ${EXPLORE_MESSAGE_FIELDS}\n }\n remainingToday\n }\n }\n`;\n\n// ============================================================================\n// Response envelopes (what `client.query`/`client.mutate` resolve `data` to)\n// ============================================================================\n\nexport interface ExploreCatalogQueryData {\n exploreCatalog: ExploreCatalog;\n}\n\nexport interface ExploreMessageQueryData {\n exploreMessage: ExploreMessage | null;\n}\n\nexport interface SendExploreMessageMutationData {\n sendExploreMessage: SendExploreMessageResult;\n}\n\n/**\n * Record that the visitor followed a link the answer offered.\n *\n * Fire-and-forget: the browser is navigating away as this goes out, so the result is never\n * waited on and a failure is never surfaced. The server reports `recorded: false` rather\n * than erroring for anything it cannot attribute.\n */\nexport const RECORD_EXPLORE_CLICK_MUTATION = /* GraphQL */ `\n mutation RecordExploreClick($input: RecordExploreClickInput!) {\n recordExploreClick(input: $input) {\n recorded\n }\n }\n`;\n\n/**\n * Mint a read-only link to this conversation.\n *\n * The returned secret is NOT the conversation token — it opens a read-only view and cannot\n * be used to continue the thread, so it is safe to put in a URL that gets forwarded.\n */\nexport const CREATE_EXPLORE_SHARE_LINK_MUTATION = /* GraphQL */ `\n mutation CreateExploreShareLink($conversationToken: String!) {\n createExploreShareLink(conversationToken: $conversationToken) {\n shareToken\n }\n }\n`;\n","import type { WebsiteSwitcherProduct } from \"../components/website-switcher\";\n\n/**\n * Canonical Burdenoff ecosystem product list used by WebsiteSwitcher.\n *\n * Sourced from `~/products/websites/burdenoff-website/src/data/products.ts`.\n * Keep this in sync when products are added, renamed, or moved.\n */\nexport const ECOSYSTEM_PRODUCTS: WebsiteSwitcherProduct[] = [\n {\n slug: \"workspaces\",\n name: \"Workspaces\",\n websiteUrl: \"https://burdenoff.com\",\n },\n {\n slug: \"vibecontrols\",\n name: \"VibeControls\",\n websiteUrl: \"https://vibecontrols.com\",\n },\n {\n slug: \"fluidgrids\",\n name: \"FluidGrids\",\n websiteUrl: \"https://fluidgrids.com\",\n },\n // Botlit ships on botlit.ai — botlit.com does not resolve.\n { slug: \"botlit\", name: \"Botlit\", websiteUrl: \"https://www.botlit.ai\" },\n {\n slug: \"bigconsole\",\n name: \"BigConsole\",\n websiteUrl: \"https://bigconsole.com\",\n },\n {\n slug: \"semanticfed\",\n name: \"SemanticFed\",\n websiteUrl: \"https://semanticfed.com\",\n },\n {\n slug: \"intelwatchtower\",\n name: \"IntelWatchtower\",\n websiteUrl: \"https://intelwatchtower.com\",\n },\n { slug: \"buildmyiq\", name: \"BuildMyIQ\", websiteUrl: \"https://buildmyiq.com\" },\n {\n slug: \"assethandler\",\n name: \"AssetHandler\",\n websiteUrl: \"https://assethandler.com\",\n },\n {\n slug: \"crewfoundry\",\n name: \"CrewFoundry\",\n websiteUrl: \"https://crewfoundry.com\",\n },\n {\n slug: \"planmagnet\",\n name: \"PlanMagnet\",\n websiteUrl: \"https://planmagnet.com\",\n },\n {\n slug: \"eventfullymanaged\",\n name: \"EventfullyManaged\",\n websiteUrl: \"https://eventfullymanaged.com\",\n },\n {\n slug: \"headshotmarketing\",\n name: \"HeadshotMarketing\",\n websiteUrl: \"https://headshotmarketing.com\",\n },\n {\n slug: \"technospam\",\n name: \"TechnoSpam\",\n websiteUrl: \"https://technospam.com\",\n },\n { slug: \"kadaikodi\", name: \"Kadaikodi\", websiteUrl: \"https://kadaikodi.com\" },\n {\n slug: \"movethewheels\",\n name: \"MoveTheWheels\",\n websiteUrl: \"https://movethewheels.com\",\n },\n {\n slug: \"healthybowl\",\n name: \"Healthy Bowl\",\n websiteUrl: \"https://gethealthybowl.com\",\n },\n { slug: \"ggnomad\", name: \"GGNomad\", websiteUrl: \"https://ggnomad.com\" },\n {\n slug: \"timecampus\",\n name: \"TimeCampus\",\n websiteUrl: \"https://timecampus.com\",\n },\n {\n slug: \"manufacturedops\",\n name: \"ManufacturedOps\",\n websiteUrl: \"https://manufacturedops.com\",\n },\n {\n slug: \"theglobalfuel\",\n name: \"TheGlobalFuel\",\n websiteUrl: \"https://theglobalfuel.com\",\n },\n {\n slug: \"housingvista\",\n name: \"HousingVista\",\n websiteUrl: \"https://housingvista.com\",\n },\n {\n slug: \"proserviceworld\",\n name: \"ProServiceWorld\",\n websiteUrl: \"https://proserviceworld.com\",\n },\n {\n slug: \"mybodyshield\",\n name: \"MyBodyShield\",\n websiteUrl: \"https://mybodyshield.com\",\n },\n {\n slug: \"artistrybase\",\n name: \"ArtistryBase\",\n websiteUrl: \"https://artistrybase.com\",\n },\n {\n slug: \"theculturepost\",\n name: \"TheCulturePost\",\n websiteUrl: \"https://theculturepost.com\",\n },\n { slug: \"collabkin\", name: \"CollabKin\", websiteUrl: \"https://collabkin.com\" },\n {\n slug: \"comradecircle\",\n name: \"ComradeCircle\",\n websiteUrl: \"https://comradecircle.com\",\n },\n {\n slug: \"brainyrich\",\n name: \"BrainyRich\",\n websiteUrl: \"https://brainyrich.com\",\n },\n {\n slug: \"cosmicintersection\",\n name: \"CosmicIntersection\",\n websiteUrl: \"https://cosmicintersection.com\",\n },\n {\n slug: \"govcitizenhub\",\n name: \"GovCitizenHub\",\n websiteUrl: \"https://govcitizenhub.com\",\n },\n {\n slug: \"adaptercloud\",\n name: \"AdapterCloud\",\n websiteUrl: \"https://adaptercloud.com\",\n },\n {\n slug: \"subscriberbot\",\n name: \"Subscriber Bot\",\n websiteUrl: \"https://subscriberbot.com\",\n },\n {\n slug: \"hookmovies\",\n name: \"HookMovies\",\n websiteUrl: \"https://hookmovies.com\",\n },\n {\n slug: \"coolandlovely\",\n name: \"CoolAndLovely\",\n websiteUrl: \"https://coolandlovely.com\",\n },\n {\n slug: \"atheletebridge\",\n name: \"AthleteBridge\",\n websiteUrl: \"https://atheletebridge.com\",\n },\n {\n slug: \"labsofscience\",\n name: \"LabsOfScience\",\n websiteUrl: \"https://labsofscience.com\",\n },\n {\n slug: \"ecoimpacthub\",\n name: \"EcoImpactHub\",\n websiteUrl: \"https://ecoimpacthub.com\",\n },\n];\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * useExploreChat — the `/explore` conversation state machine.\n *\n * Implements the client half of CONTRACT.md §1: a **submit + poll** exchange.\n * `sendExploreMessage` returns immediately with a PENDING assistant message;\n * the answer arrives by polling `exploreMessage(conversationToken, id)` roughly\n * every 1.5s until it reports COMPLETED or FAILED. Both gateway hops cap a\n * subgraph call at 20s while a turn takes 5-60s, which is why there is no\n * request that simply waits for the answer.\n *\n * Design rules this hook exists to enforce:\n *\n * 1. **The catalog never gates the first paint.** `catalog` is populated with a\n * static fallback synchronously, so `ExplorePage` can render its `<h1>` on\n * the very first render. The websites' prerender waits for an `h1`; if that\n * heading depended on a network round-trip, 38 static builds would capture a\n * blank page.\n * 2. **Polls bypass the query cache.** `client.query(..., { cache: false })` —\n * the default 5-minute cache would hand every later poll the first PENDING\n * snapshot and the answer would never appear.\n * 3. **Nothing outlives the component.** Unmount and `stop()` both cancel the\n * poll chain through a generation counter, so a late response can never\n * write into an unmounted tree.\n */\n\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useWebSDK } from \"../client/provider\";\nimport {\n EXPLORE_CATALOG_QUERY,\n EXPLORE_MESSAGE_QUERY,\n CREATE_EXPLORE_SHARE_LINK_MUTATION,\n RECORD_EXPLORE_CLICK_MUTATION,\n SEND_EXPLORE_MESSAGE_MUTATION,\n} from \"../components/explore-types\";\nimport { ECOSYSTEM_PRODUCTS } from \"../data/products\";\nimport { getRecaptchaV3Token } from \"../utils/recaptcha-v3\";\n\nimport type {\n ExploreCatalog,\n ExploreCatalogQueryData,\n ExploreLimits,\n ExploreMessage,\n ExploreMessageQueryData,\n SendExploreMessageInput,\n SendExploreMessageMutationData,\n} from \"../components/explore-types\";\n\n// ============================================================================\n// Public types\n// ============================================================================\n\n/**\n * Where the conversation is right now.\n *\n * - `loading` — catalog request in flight (the fallback catalog is already\n * rendered, so this is a refinement, not a blank screen).\n * - `ready` — idle; the composer accepts input.\n * - `sending` — `sendExploreMessage` in flight.\n * - `streaming` — polling the assistant turn; `activity` is live.\n * - `error` — the last turn failed; `retry()` is meaningful and the\n * composer stays usable.\n * - `limited` — rate limited; the composer is disabled.\n * - `disabled` — `exploreCatalog.enabled === false`.\n */\nexport type ExploreChatPhase =\n | \"loading\"\n | \"ready\"\n | \"sending\"\n | \"streaming\"\n | \"error\"\n | \"limited\"\n | \"disabled\";\n\n/** Coarse bucket the UI switches its banner copy and affordances on. */\nexport type ExploreChatErrorKind =\n | \"rate-limit\"\n | \"captcha\"\n | \"timeout\"\n | \"network\"\n | \"disabled\"\n | \"validation\"\n | \"unknown\";\n\nexport interface ExploreChatError {\n /** UI bucket. */\n kind: ExploreChatErrorKind;\n /** Raw `extensions.code` (or a client-side code such as `TIMEOUT`). */\n code: string;\n /** Human-readable, safe to render. */\n message: string;\n /** Whether re-sending the same message could plausibly succeed. */\n retryable: boolean;\n}\n\nexport interface UseExploreChatOptions {\n /** Slug of the product site this page is on — a soft hint to the harness. */\n productSlug?: string;\n /** Full URL of the page, forwarded as `pageUrl`. */\n pageUrl?: string;\n /** BCP-47 locale, forwarded as `locale`. */\n locale?: string;\n /** Poll cadence in ms. Default 1500 (CONTRACT.md §1). */\n pollIntervalMs?: number;\n /** Give up on a turn after this long. Default 90000 (the edge poll timeout). */\n pollTimeoutMs?: number;\n /**\n * Prompts to offer when `exploreCatalog` supplies none. Resolution order is\n * catalog → this option → {@link DEFAULT_EXPLORE_EXAMPLE_PROMPTS}, so a site\n * can ship product-specific prompts without waiting on the backend and still\n * be overridden centrally once the catalog carries them.\n */\n examplePrompts?: string[];\n /** localStorage key for the ACTIVE conversation. Default `boff.explore.v1`. */\n storageKey?: string;\n /** Persist the conversation across reloads within the tab. Default true. */\n persist?: boolean;\n /** Called with the message text each time a send is accepted locally. */\n onSend?: (message: string) => void;\n}\n\nexport interface UseExploreChatResult {\n phase: ExploreChatPhase;\n /** Never null — starts as the static fallback, upgraded by the server. */\n catalog: ExploreCatalog;\n messages: ExploreMessage[];\n /** Latest progress line of the in-flight turn, or null when idle. */\n activity: string | null;\n /** Messages left today for this visitor, when the server reports it. */\n remainingToday: number | null;\n error: ExploreChatError | null;\n /** Product the visitor pinned the conversation to, or null for \"all\". */\n focusProduct: string | null;\n setFocusProduct: (slug: string | null) => void;\n send: (message: string) => Promise<void>;\n /** Stop polling and keep whatever text has streamed so far. */\n stop: () => void;\n /** Re-send the last message after a failed turn. */\n retry: () => void;\n /** Clear the conversation and the persisted session. */\n reset: () => void;\n /** Past conversations held in THIS browser, newest first. */\n history: ArchivedExploreConversation[];\n /** Reopen a past conversation and continue it. */\n openConversation: (token: string) => void;\n /** Forget one past conversation (local only). */\n deleteConversation: (token: string) => void;\n /** Forget every past conversation held in this browser. */\n clearHistory: () => void;\n /**\n * Record that the visitor followed a link this answer offered. Fire-and-forget — never\n * awaited, never throws, and must never delay the navigation it is reporting on.\n */\n recordClick: (\n messageId: string,\n kind: \"CTA\" | \"REFERENCE\",\n url: string,\n ) => void;\n /**\n * Mint a read-only link to this conversation, or null when there is nothing to share yet.\n * The secret returned is not the conversation token and cannot continue the thread.\n */\n createShareLink: () => Promise<string | null>;\n canSend: boolean;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = \"boff.explore.v1\";\n/** Where past conversations live. Derived from the active key so a custom key stays paired. */\nconst HISTORY_SUFFIX = \".history\";\n/**\n * How many past conversations to keep, and how many messages of each. Bounded on purpose:\n * localStorage is a few MB per origin and shared with everything else the site stores, so an\n * unbounded archive would eventually start throwing QuotaExceededError on write.\n */\nconst MAX_ARCHIVED_CONVERSATIONS = 15;\nconst MAX_ARCHIVED_MESSAGES = 20;\nconst DEFAULT_POLL_INTERVAL_MS = 1_500;\n/** Matches `EXPLORE_AGENT_TIMEOUT_MS` (CONTRACT.md §3) — the edge gives up too. */\nconst DEFAULT_POLL_TIMEOUT_MS = 90_000;\n/** Per-poll HTTP timeout. Short: a stuck poll must not stall the chain. */\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n/** The submit hop enqueues a job; generous but well under the gateway's 20s. */\nconst SEND_REQUEST_TIMEOUT_MS = 18_000;\n/** Transient poll failures tolerated before the turn is declared dead. */\nconst MAX_CONSECUTIVE_POLL_FAILURES = 4;\n/** Cap on what goes into localStorage — a conversation must not grow unbounded. */\nconst MAX_PERSISTED_MESSAGES = 40;\n\n/** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */\nexport const FALLBACK_EXPLORE_LIMITS: ExploreLimits = {\n maxMessageLength: 2000,\n maxTurnsPerConversation: 20,\n messagesPerDay: 100,\n historyTurns: 6,\n};\n\n/**\n * Prompts shown when neither the catalog nor the consumer supplies any.\n * Deliberately product-agnostic — this SDK renders on 38 different sites.\n */\nexport const DEFAULT_EXPLORE_EXAMPLE_PROMPTS: string[] = [\n \"What does this product actually do?\",\n \"Which Burdenoff product fits my team?\",\n \"How do I get started, step by step?\",\n \"What does it integrate with?\",\n];\n\nconst FALLBACK_WELCOME_TITLE = \"Ask anything about our products\";\nconst FALLBACK_WELCOME_BODY =\n \"Get straight answers drawn from our product documentation and public pages — with links back to the exact page each answer came from.\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction buildFallbackCatalog(examplePrompts?: string[]): ExploreCatalog {\n return {\n enabled: true,\n products: ECOSYSTEM_PRODUCTS.map((p) => ({\n slug: p.slug,\n name: p.name,\n tagline: null,\n website: p.websiteUrl,\n })),\n examplePrompts: examplePrompts?.length\n ? examplePrompts\n : DEFAULT_EXPLORE_EXAMPLE_PROMPTS,\n welcomeTitle: FALLBACK_WELCOME_TITLE,\n welcomeBody: FALLBACK_WELCOME_BODY,\n limits: FALLBACK_EXPLORE_LIMITS,\n captchaRequired: false,\n recaptchaSiteKey: null,\n };\n}\n\n/**\n * Harden a server catalog against partial/degraded responses so a missing\n * field can never blank the page or produce `maxMessageLength: 0` (which would\n * silently disable the composer).\n */\nfunction normalizeCatalog(\n raw: ExploreCatalog,\n fallback: ExploreCatalog,\n): ExploreCatalog {\n return {\n enabled: raw.enabled !== false,\n products: raw.products?.length ? raw.products : fallback.products,\n examplePrompts: raw.examplePrompts?.length\n ? raw.examplePrompts\n : fallback.examplePrompts,\n welcomeTitle: raw.welcomeTitle || fallback.welcomeTitle,\n welcomeBody: raw.welcomeBody || fallback.welcomeBody,\n limits: {\n maxMessageLength:\n raw.limits?.maxMessageLength || fallback.limits.maxMessageLength,\n maxTurnsPerConversation:\n raw.limits?.maxTurnsPerConversation ||\n fallback.limits.maxTurnsPerConversation,\n messagesPerDay:\n raw.limits?.messagesPerDay || fallback.limits.messagesPerDay,\n historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns,\n },\n captchaRequired: raw.captchaRequired === true,\n recaptchaSiteKey: raw.recaptchaSiteKey ?? null,\n };\n}\n\nconst RATE_LIMIT_CODES = new Set([\n \"RATE_LIMITED\",\n \"HTTP_429\",\n \"EXPLORE_GLOBAL_LIMIT\",\n]);\nconst CAPTCHA_CODES = new Set([\"CAPTCHA_FAILED\", \"CAPTCHA_REQUIRED\"]);\nconst NETWORK_CODES = new Set([\n \"NETWORK_ERROR\",\n \"UPSTREAM_UNAVAILABLE\",\n \"CONVERSATION_BUSY\",\n \"PROVIDER_ERROR\",\n \"QUEUE_FULL\",\n]);\nconst VALIDATION_CODES = new Set([\n \"MESSAGE_TOO_LONG\",\n \"MESSAGE_EMPTY\",\n \"CONVERSATION_LIMIT\",\n \"INVALID_INPUT\",\n]);\n\n/**\n * Map a `extensions.code` (or a client-side transport code) onto the bucket the\n * UI renders. Unknown codes are treated as retryable — a transient backend\n * condition we have not enumerated is far more likely than a permanent one.\n */\nexport function classifyExploreError(\n code: string | null | undefined,\n serverMessage?: string | null,\n): ExploreChatError {\n const c = code ?? \"UNKNOWN\";\n if (RATE_LIMIT_CODES.has(c)) {\n return {\n kind: \"rate-limit\",\n code: c,\n message:\n \"You've reached the message limit for now. Please try again later.\",\n retryable: false,\n };\n }\n if (CAPTCHA_CODES.has(c)) {\n return {\n kind: \"captcha\",\n code: c,\n message:\n \"We couldn't verify that you're human. Please try sending that again.\",\n retryable: true,\n };\n }\n if (c === \"TIMEOUT\" || c === \"TOOL_BUDGET\") {\n return {\n kind: \"timeout\",\n code: c,\n message: \"That answer took too long to come back. Try asking again.\",\n retryable: true,\n };\n }\n if (NETWORK_CODES.has(c)) {\n return {\n kind: \"network\",\n code: c,\n message:\n \"We couldn't reach the assistant just now. Check your connection and try again.\",\n retryable: true,\n };\n }\n if (c === \"EXPLORE_DISABLED\") {\n return {\n kind: \"disabled\",\n code: c,\n message: \"Explore is unavailable at the moment. Please check back soon.\",\n retryable: false,\n };\n }\n if (VALIDATION_CODES.has(c)) {\n return {\n kind: \"validation\",\n code: c,\n message: serverMessage || \"That message couldn't be sent.\",\n retryable: false,\n };\n }\n if (c === \"EMPTY_ANSWER\") {\n return {\n kind: \"unknown\",\n code: c,\n message:\n \"No answer came back for that one. Try rephrasing, or ask something more specific.\",\n retryable: true,\n };\n }\n return {\n kind: \"unknown\",\n code: c,\n message: serverMessage || \"Something went wrong. Please try again.\",\n retryable: true,\n };\n}\n\ninterface PersistedExploreState {\n conversationToken: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n}\n\n/** One past conversation, as shown in the history list and restored on click. */\nexport interface ArchivedExploreConversation {\n token: string;\n /** First thing the visitor asked — the human-readable label for the thread. */\n title: string;\n /** ISO timestamp of the last message in the thread. */\n updatedAt: string;\n messageCount: number;\n focusProduct: string | null;\n messages: ExploreMessage[];\n}\n\nfunction historyKey(key: string): string {\n return `${key}${HISTORY_SUFFIX}`;\n}\n\nfunction readArchive(key: string): ArchivedExploreConversation[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(historyKey(key));\n if (!raw) return [];\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (entry): entry is ArchivedExploreConversation =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as ArchivedExploreConversation).token === \"string\" &&\n Array.isArray((entry as ArchivedExploreConversation).messages),\n );\n } catch {\n return [];\n }\n}\n\nfunction writeArchive(\n key: string,\n entries: ArchivedExploreConversation[],\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (entries.length === 0) {\n window.localStorage.removeItem(historyKey(key));\n return;\n }\n window.localStorage.setItem(historyKey(key), JSON.stringify(entries));\n } catch {\n /* private mode or quota — the archive is a convenience, never load-bearing */\n }\n}\n\n/**\n * Fold the given thread into the archive, newest first.\n *\n * Upsert by token rather than append: the same conversation is archived after every completed\n * turn so an abruptly closed tab still leaves a record, and appending would fill the list with\n * duplicates of one thread.\n */\nfunction upsertArchive(\n key: string,\n thread: {\n token: string | null;\n messages: ExploreMessage[];\n focusProduct: string | null;\n },\n): ArchivedExploreConversation[] {\n if (!thread.token) return readArchive(key);\n const real = thread.messages.filter(\n (m) => m.content.trim() !== \"\" || m.role === \"USER\",\n );\n if (real.length === 0) return readArchive(key);\n\n const firstUser = real.find((m) => m.role === \"USER\");\n const entry: ArchivedExploreConversation = {\n token: thread.token,\n title: (firstUser?.content ?? \"Conversation\").trim().slice(0, 80),\n updatedAt: real[real.length - 1]?.createdAt ?? new Date().toISOString(),\n messageCount: real.length,\n focusProduct: thread.focusProduct,\n messages: real.slice(-MAX_ARCHIVED_MESSAGES),\n };\n\n const rest = readArchive(key).filter((e) => e.token !== entry.token);\n const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);\n writeArchive(key, next);\n return next;\n}\n\nfunction readPersisted(key: string): PersistedExploreState | null {\n // SSR / prerender: there is no localStorage, and reading one during the\n // first client render would desync hydration anyway.\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\") return null;\n const record = parsed as Partial<PersistedExploreState>;\n return {\n conversationToken:\n typeof record.conversationToken === \"string\"\n ? record.conversationToken\n : null,\n messages: Array.isArray(record.messages)\n ? record.messages.slice(-MAX_PERSISTED_MESSAGES)\n : [],\n focusProduct:\n typeof record.focusProduct === \"string\" ? record.focusProduct : null,\n };\n } catch {\n /* corrupt or unavailable storage — start a fresh conversation */\n return null;\n }\n}\n\n/**\n * A turn that never produced any text is worth dropping rather than rendering\n * as an empty bubble — used by `stop()` and by the failure paths.\n */\nfunction visibleText(message: ExploreMessage): string {\n return message.content || message.partialContent || \"\";\n}\n\nfunction countUserTurns(messages: ExploreMessage[]): number {\n return messages.filter((m) => m.role === \"USER\").length;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExploreChat(\n options: UseExploreChatOptions = {},\n): UseExploreChatResult {\n const {\n productSlug,\n pageUrl,\n locale,\n examplePrompts,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,\n storageKey = DEFAULT_STORAGE_KEY,\n persist = true,\n onSend,\n } = options;\n\n const client = useWebSDK();\n\n // The fallback catalog is the initial value AND the merge base for the\n // server response. Keyed on the prompt CONTENT, not the array identity —\n // a consumer passing an inline `examplePrompts={[...]}` literal would\n // otherwise rebuild it every render and re-fire the catalog effect.\n const promptKey = JSON.stringify(examplePrompts ?? []);\n const fallbackCatalog = useMemo(\n () => buildFallbackCatalog(JSON.parse(promptKey) as string[]),\n [promptKey],\n );\n\n const [catalog, setCatalog] = useState<ExploreCatalog>(fallbackCatalog);\n const [messages, setMessages] = useState<ExploreMessage[]>([]);\n const [phase, setPhase] = useState<ExploreChatPhase>(\"loading\");\n const [error, setError] = useState<ExploreChatError | null>(null);\n const [remainingToday, setRemainingToday] = useState<number | null>(null);\n const [focusProduct, setFocusProductState] = useState<string | null>(null);\n const [turnCount, setTurnCount] = useState(0);\n // Mirror of `messages` for callbacks that must not re-create on every message.\n const messagesRef = useRef<ExploreMessage[]>([]);\n const [archive, setArchive] = useState<ArchivedExploreConversation[]>([]);\n\n const [hydrated, setHydrated] = useState(false);\n\n // Refs mirror the state that async callbacks read, so `send`/`poll` never\n // close over a stale value and never need to be re-created mid-flight.\n const mountedRef = useRef(true);\n const pollGenerationRef = useRef(0);\n const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const conversationTokenRef = useRef<string | null>(null);\n const catalogRef = useRef<ExploreCatalog>(fallbackCatalog);\n const turnCountRef = useRef(0);\n const focusProductRef = useRef<string | null>(null);\n const lastSentTextRef = useRef<string | null>(null);\n const inFlightRef = useRef(false);\n\n catalogRef.current = catalog;\n\n const clearPollTimer = useCallback(() => {\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n }, []);\n\n /** Invalidate any running poll chain. Late responses become no-ops. */\n const cancelPolling = useCallback(() => {\n pollGenerationRef.current += 1;\n clearPollTimer();\n }, [clearPollTimer]);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n pollGenerationRef.current += 1;\n if (pollTimerRef.current !== null) {\n clearTimeout(pollTimerRef.current);\n pollTimerRef.current = null;\n }\n };\n }, []);\n\n // --------------------------------------------------------------------------\n // Hydrate from localStorage (effect, not lazy state, so the FIRST client\n // render matches the prerendered HTML and hydration stays clean).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist) {\n setHydrated(true);\n return;\n }\n setArchive(readArchive(storageKey));\n const stored = readPersisted(storageKey);\n if (stored) {\n conversationTokenRef.current = stored.conversationToken;\n focusProductRef.current = stored.focusProduct;\n // A turn that was still streaming when the tab was closed can never be\n // resumed from here — the poll chain is gone. Land it as-is.\n const settled = stored.messages.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"COMPLETED\", content: text }];\n });\n setMessages(settled);\n setFocusProductState(stored.focusProduct);\n const turns = countUserTurns(settled);\n turnCountRef.current = turns;\n setTurnCount(turns);\n }\n setHydrated(true);\n }, [persist, storageKey]);\n\n // --------------------------------------------------------------------------\n // Persist (after hydration, so the initial empty state never wipes storage).\n // --------------------------------------------------------------------------\n useEffect(() => {\n if (!persist || !hydrated || typeof window === \"undefined\") return;\n try {\n const payload: PersistedExploreState = {\n conversationToken: conversationTokenRef.current,\n messages: messages.slice(-MAX_PERSISTED_MESSAGES),\n focusProduct,\n };\n // Nothing worth restoring (fresh page, or just after reset()): drop the\n // key entirely rather than leaving an empty husk behind.\n if (\n !payload.conversationToken &&\n payload.messages.length === 0 &&\n !payload.focusProduct\n ) {\n window.localStorage.removeItem(storageKey);\n return;\n }\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n /* private mode / quota exceeded — persistence is a nicety, not a feature */\n }\n }, [persist, hydrated, storageKey, messages, focusProduct]);\n\n // Mirror messages into a ref for callbacks, and fold a settled thread into the archive.\n // Archiving on every settled turn (not only on reset) is what makes an abruptly closed tab\n // still leave a record the visitor can come back to.\n useEffect(() => {\n messagesRef.current = messages;\n if (!persist || !hydrated) return;\n const settled = messages.some(\n (m) =>\n m.role === \"ASSISTANT\" &&\n (m.status === \"COMPLETED\" || m.status === \"FAILED\"),\n );\n if (!settled) return;\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages,\n focusProduct: focusProductRef.current,\n }),\n );\n }, [messages, persist, hydrated, storageKey]);\n\n // --------------------------------------------------------------------------\n // Catalog. Cached (the default) — it is per-page-load configuration, not a\n // poll. A failure keeps the fallback so the page NEVER renders blank.\n // --------------------------------------------------------------------------\n useEffect(() => {\n let cancelled = false;\n const load = async () => {\n const res = await client.query<ExploreCatalogQueryData>(\n EXPLORE_CATALOG_QUERY,\n { productSlug: productSlug ?? null },\n );\n if (cancelled || !mountedRef.current) return;\n\n const raw = res.data?.exploreCatalog;\n if (res.errors?.length || !raw) {\n console.warn(\n \"[WebSDK] exploreCatalog unavailable — using the built-in fallback catalog\",\n res.errors?.[0]?.message,\n );\n setPhase((prev) => (prev === \"loading\" ? \"ready\" : prev));\n return;\n }\n\n const next = normalizeCatalog(raw, fallbackCatalog);\n setCatalog(next);\n catalogRef.current = next;\n setPhase((prev) => {\n if (!next.enabled) return \"disabled\";\n return prev === \"loading\" ? \"ready\" : prev;\n });\n };\n void load();\n return () => {\n cancelled = true;\n };\n }, [client, productSlug, fallbackCatalog]);\n\n // --------------------------------------------------------------------------\n // Poll chain\n // --------------------------------------------------------------------------\n const startPolling = useCallback(\n (conversationToken: string, messageId: string) => {\n pollGenerationRef.current += 1;\n const generation = pollGenerationRef.current;\n const startedAt = Date.now();\n let consecutiveFailures = 0;\n\n const isStale = () =>\n !mountedRef.current || generation !== pollGenerationRef.current;\n\n const finishWithError = (chatError: ExploreChatError) => {\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.id !== messageId) return [m];\n const text = visibleText(m);\n if (!text) return [];\n return [{ ...m, status: \"FAILED\", content: text }];\n }),\n );\n setError(chatError);\n setPhase(chatError.kind === \"rate-limit\" ? \"limited\" : \"error\");\n };\n\n const tick = async () => {\n if (isStale()) return;\n\n if (Date.now() - startedAt > pollTimeoutMs) {\n finishWithError(classifyExploreError(\"TIMEOUT\"));\n return;\n }\n\n // `cache: false` is load-bearing — see CONTRACT.md §4.\n const res = await client.query<ExploreMessageQueryData>(\n EXPLORE_MESSAGE_QUERY,\n { conversationToken, id: messageId },\n { cache: false, timeoutMs: POLL_REQUEST_TIMEOUT_MS },\n );\n if (isStale()) return;\n\n const first = res.errors?.[0];\n if (first) {\n const code =\n typeof first.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first.message);\n // Hard stops: retrying a rate limit or a disabled feature is pointless.\n if (!classified.retryable) {\n finishWithError(classified);\n return;\n }\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classified);\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n const message = res.data?.exploreMessage;\n if (!message) {\n // Can happen briefly right after submit; tolerate a few misses.\n consecutiveFailures += 1;\n if (consecutiveFailures >= MAX_CONSECUTIVE_POLL_FAILURES) {\n finishWithError(classifyExploreError(\"NOT_FOUND\"));\n return;\n }\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n return;\n }\n\n consecutiveFailures = 0;\n // Replace in place so `partialContent` renders as it streams.\n setMessages((prev) =>\n prev.map((m) => (m.id === messageId ? message : m)),\n );\n\n if (message.status === \"COMPLETED\") {\n inFlightRef.current = false;\n setError(null);\n setPhase(\"ready\");\n return;\n }\n if (message.status === \"FAILED\") {\n finishWithError(\n classifyExploreError(message.errorCode ?? \"UPSTREAM_UNAVAILABLE\"),\n );\n return;\n }\n\n setPhase(\"streaming\");\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n };\n\n // First poll after one interval — the turn cannot possibly be done sooner.\n pollTimerRef.current = setTimeout(() => void tick(), pollIntervalMs);\n },\n [client, pollIntervalMs, pollTimeoutMs],\n );\n\n // --------------------------------------------------------------------------\n // send\n // --------------------------------------------------------------------------\n const submit = useCallback(\n async (\n text: string,\n optimisticId: string,\n captchaAttempt: number,\n ): Promise<void> => {\n const activeCatalog = catalogRef.current;\n\n let recaptchaToken: string | undefined;\n if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {\n try {\n recaptchaToken = await getRecaptchaV3Token(\n activeCatalog.recaptchaSiteKey,\n );\n } catch (err) {\n console.warn(\"[WebSDK] reCAPTCHA v3 token could not be minted\", err);\n // Send without a token and let the backend decide — it owns the\n // policy, and a blocked third-party script must not silently kill\n // the whole feature.\n }\n }\n\n const input: SendExploreMessageInput = {\n message: text,\n ...(conversationTokenRef.current\n ? { conversationToken: conversationTokenRef.current }\n : {}),\n ...(focusProductRef.current || productSlug\n ? { productSlug: focusProductRef.current ?? productSlug }\n : {}),\n ...(recaptchaToken ? { recaptchaToken } : {}),\n ...(locale ? { locale } : {}),\n ...(pageUrl ? { pageUrl } : {}),\n };\n\n const res = await client.mutate<SendExploreMessageMutationData>(\n SEND_EXPLORE_MESSAGE_MUTATION,\n { input },\n { timeoutMs: SEND_REQUEST_TIMEOUT_MS },\n );\n if (!mountedRef.current) return;\n\n const first = res.errors?.[0];\n const result = res.data?.sendExploreMessage;\n\n if (first || !result) {\n const code =\n typeof first?.extensions?.code === \"string\"\n ? first.extensions.code\n : undefined;\n const classified = classifyExploreError(code, first?.message);\n\n // CAPTCHA_FAILED: one silent re-mint + re-send before bothering the\n // visitor. v3 tokens expire in ~2 minutes and are single-use, so a\n // stale one is a routine, self-healing failure.\n if (classified.kind === \"captcha\" && captchaAttempt === 0) {\n await submit(text, optimisticId, 1);\n return;\n }\n\n inFlightRef.current = false;\n setError(classified);\n setPhase(classified.kind === \"rate-limit\" ? \"limited\" : \"error\");\n return;\n }\n\n conversationTokenRef.current = result.conversation.token;\n turnCountRef.current = result.conversation.turnCount;\n setTurnCount(result.conversation.turnCount);\n setRemainingToday(result.remainingToday ?? null);\n\n const userMessage = result.userMessage;\n const assistantMessage = result.assistantMessage;\n\n // Swap the optimistic user bubble for the server's, then append the\n // PENDING assistant turn that the poll chain will fill in. The `some`\n // guard keeps the visitor's words on screen even in the impossible case\n // where the optimistic bubble is already gone.\n setMessages((prev) => {\n const replaced = prev.some((m) => m.id === optimisticId)\n ? prev.map((m) => (m.id === optimisticId ? userMessage : m))\n : [...prev, userMessage];\n return [...replaced, assistantMessage];\n });\n\n if (\n assistantMessage.status === \"COMPLETED\" ||\n assistantMessage.status === \"FAILED\"\n ) {\n inFlightRef.current = false;\n if (assistantMessage.status === \"FAILED\") {\n const classified = classifyExploreError(\n assistantMessage.errorCode ?? \"UPSTREAM_UNAVAILABLE\",\n );\n setError(classified);\n setPhase(\"error\");\n } else {\n setPhase(\"ready\");\n }\n return;\n }\n\n setPhase(\"streaming\");\n startPolling(result.conversation.token, assistantMessage.id);\n },\n [client, locale, pageUrl, productSlug, startPolling],\n );\n\n const send = useCallback(\n async (message: string): Promise<void> => {\n const text = message.trim();\n if (!text) return;\n if (inFlightRef.current) return;\n\n const activeCatalog = catalogRef.current;\n if (!activeCatalog.enabled) {\n setError(classifyExploreError(\"EXPLORE_DISABLED\"));\n setPhase(\"disabled\");\n return;\n }\n if (text.length > activeCatalog.limits.maxMessageLength) {\n setError({\n kind: \"validation\",\n code: \"MESSAGE_TOO_LONG\",\n message: `That message is ${text.length} characters — the limit is ${activeCatalog.limits.maxMessageLength}.`,\n retryable: false,\n });\n return;\n }\n if (\n turnCountRef.current >= activeCatalog.limits.maxTurnsPerConversation\n ) {\n setError({\n kind: \"validation\",\n code: \"CONVERSATION_LIMIT\",\n message: `This conversation has reached its ${activeCatalog.limits.maxTurnsPerConversation}-message limit. Start a new chat to keep going.`,\n retryable: false,\n });\n return;\n }\n\n inFlightRef.current = true;\n lastSentTextRef.current = text;\n setError(null);\n setPhase(\"sending\");\n cancelPolling();\n\n // Optimistic user bubble — the composer clears instantly instead of\n // waiting a network round-trip for the visitor's own words.\n const optimistic: ExploreMessage = {\n id: makeOptimisticId(),\n conversationId: conversationTokenRef.current ?? \"pending\",\n role: \"USER\",\n status: \"COMPLETED\",\n content: text,\n partialContent: null,\n activity: [],\n references: [],\n ctas: [],\n errorCode: null,\n createdAt: new Date().toISOString(),\n completedAt: new Date().toISOString(),\n };\n setMessages((prev) => [...prev, optimistic]);\n turnCountRef.current += 1;\n setTurnCount(turnCountRef.current);\n onSend?.(text);\n\n try {\n await submit(text, optimistic.id, 0);\n } catch (err) {\n if (!mountedRef.current) return;\n console.error(\"[WebSDK] Explore send failed\", err);\n inFlightRef.current = false;\n setError(classifyExploreError(\"NETWORK_ERROR\"));\n setPhase(\"error\");\n }\n },\n [cancelPolling, onSend, submit],\n );\n\n const stop = useCallback(() => {\n cancelPolling();\n inFlightRef.current = false;\n setMessages((prev) =>\n prev.flatMap<ExploreMessage>((m) => {\n if (m.role !== \"ASSISTANT\") return [m];\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return [m];\n const text = visibleText(m);\n // Nothing streamed yet — drop the placeholder instead of leaving an\n // empty bubble behind.\n if (!text) return [];\n return [\n {\n ...m,\n status: \"COMPLETED\",\n content: text,\n completedAt: new Date().toISOString(),\n },\n ];\n }),\n );\n setPhase((prev) =>\n prev === \"sending\" || prev === \"streaming\" ? \"ready\" : prev,\n );\n }, [cancelPolling]);\n\n const retry = useCallback(() => {\n const text = lastSentTextRef.current;\n if (!text) return;\n cancelPolling();\n inFlightRef.current = false;\n // Drop the failed turn (and the user bubble that produced it) so the retry\n // does not stack a duplicate pair into the transcript.\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last?.role === \"ASSISTANT\" && last.status === \"FAILED\") next.pop();\n const prior = next[next.length - 1];\n if (prior?.role === \"USER\" && prior.content === text) next.pop();\n return next;\n });\n turnCountRef.current = Math.max(0, turnCountRef.current - 1);\n setTurnCount(turnCountRef.current);\n void send(text);\n }, [cancelPolling, send]);\n\n const reset = useCallback(() => {\n // Archive the thread being left behind, so \"New chat\" never destroys history.\n setArchive(\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n }),\n );\n cancelPolling();\n inFlightRef.current = false;\n conversationTokenRef.current = null;\n lastSentTextRef.current = null;\n turnCountRef.current = 0;\n setTurnCount(0);\n setMessages([]);\n setError(null);\n setRemainingToday(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n if (typeof window !== \"undefined\") {\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n /* storage unavailable — nothing to clear */\n }\n }\n }, [cancelPolling, storageKey]);\n\n /**\n * Reopen a past conversation. The messages come from the local archive rather than the server:\n * the backend expires a job's state, and a visitor looking at their own history should see it\n * whether or not the server still holds anything. The token is restored too, so the next\n * message continues the SAME server-side conversation.\n */\n const openConversation = useCallback(\n (token: string) => {\n const entry = readArchive(storageKey).find((e) => e.token === token);\n if (!entry) return;\n // Archive whatever is on screen first, or switching away would lose it.\n upsertArchive(storageKey, {\n token: conversationTokenRef.current,\n messages: messagesRef.current,\n focusProduct: focusProductRef.current,\n });\n cancelPolling();\n inFlightRef.current = false;\n conversationTokenRef.current = entry.token;\n turnCountRef.current = entry.messages.filter(\n (m) => m.role === \"USER\",\n ).length;\n setTurnCount(turnCountRef.current);\n setMessages(entry.messages);\n focusProductRef.current = entry.focusProduct;\n setFocusProductState(entry.focusProduct);\n setError(null);\n setPhase(catalogRef.current.enabled ? \"ready\" : \"disabled\");\n setArchive(readArchive(storageKey));\n },\n [cancelPolling, storageKey],\n );\n\n /** Forget one past conversation. Local only — see the page's storage notice. */\n const deleteConversation = useCallback(\n (token: string) => {\n const next = readArchive(storageKey).filter((e) => e.token !== token);\n writeArchive(storageKey, next);\n setArchive(next);\n },\n [storageKey],\n );\n\n /** Forget every past conversation held in this browser. */\n const clearHistory = useCallback(() => {\n writeArchive(storageKey, []);\n setArchive([]);\n }, [storageKey]);\n\n const setFocusProduct = useCallback((slug: string | null) => {\n focusProductRef.current = slug;\n setFocusProductState(slug);\n }, []);\n\n const activity = useMemo<string | null>(() => {\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const m = messages[i];\n if (!m || m.role !== \"ASSISTANT\") continue;\n if (m.status !== \"PENDING\" && m.status !== \"RUNNING\") return null;\n const lines = m.activity ?? [];\n return lines.length ? (lines[lines.length - 1] ?? null) : null;\n }\n return null;\n }, [messages]);\n\n const canSend =\n (phase === \"ready\" || phase === \"error\") &&\n catalog.enabled &&\n turnCount < catalog.limits.maxTurnsPerConversation;\n\n /**\n * Tell the server the visitor followed one of the links this answer offered.\n *\n * Deliberately fire-and-forget and never awaited: the browser is navigating away as this\n * goes out, so anything that blocked on it would delay the click the visitor actually\n * made. Failures are swallowed — analytics must never break navigation.\n */\n const createShareLink = useCallback(async (): Promise<string | null> => {\n const token = conversationTokenRef.current;\n if (!token) return null;\n try {\n const result = await client.mutate<{\n createExploreShareLink?: { shareToken?: string | null } | null;\n }>(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });\n return result?.data?.createExploreShareLink?.shareToken ?? null;\n } catch {\n // Sharing is a convenience; a failure must not take the conversation down with it.\n return null;\n }\n }, [client]);\n\n const recordClick = useCallback(\n (messageId: string, kind: \"CTA\" | \"REFERENCE\", url: string): void => {\n const token = conversationTokenRef.current;\n if (!token) return;\n try {\n void client\n .mutate(RECORD_EXPLORE_CLICK_MUTATION, {\n input: { conversationToken: token, messageId, kind, url },\n })\n .catch(() => {\n /* the visitor is mid-navigation; there is nothing useful to do here */\n });\n } catch {\n /* client unavailable — same reasoning */\n }\n },\n [client],\n );\n\n return {\n phase,\n catalog,\n messages,\n activity,\n remainingToday,\n error,\n focusProduct,\n setFocusProduct,\n send,\n stop,\n retry,\n reset,\n canSend,\n history: archive,\n openConversation,\n deleteConversation,\n clearHistory,\n recordClick,\n createShareLink,\n };\n}\n\n/**\n * Client-only id for the optimistic user bubble, swapped for the server's\n * `userMessage.id` as soon as the mutation resolves. The counter only has to\n * make ids unique within a tab, never across one.\n */\nlet optimisticCounter = 0;\n\nfunction makeOptimisticId(): string {\n optimisticCounter += 1;\n return `boff-explore-local-${Date.now()}-${optimisticCounter}`;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Dictation for the explore composer, on the browser's own speech recogniser.\n *\n * Uses the Web Speech API directly — no dependency, no network call of our own, no audio ever\n * leaving the browser through us. Support is genuinely partial (Chrome, Edge and Safari expose\n * it, most commonly behind the `webkit` prefix; Firefox does not implement it at all), so the\n * caller MUST hide the microphone entirely when `supported` is false rather than offering a\n * control that cannot work.\n *\n * Interim results are surfaced separately from final ones so the composer can show speech\n * appearing live while only committing settled text to the draft.\n *\n * ## Mobile\n *\n * Mobile took three separate fixes, each of which looked like the whole problem:\n *\n * 1. **The prompt never appeared.** `recognition.start()` raises the permission prompt on\n * desktop Chrome but on Android Chrome and iOS fires `not-allowed` without showing\n * anything, so a visitor who had never been asked was told to change a browser setting.\n * `getUserMedia` is what actually prompts, so it is primed first.\n * 2. **Granting still failed.** Recognition opens its OWN capture, and starting it in the same\n * tick that the primed stream is being torn down races that teardown. It now waits for the\n * release, and retries once — Android frequently refuses the first attempt after a\n * permission is newly granted and accepts the second.\n * 3. **`continuous` is not honoured on mobile.** Android Chrome ends the session after a\n * single utterance regardless, and asking for continuous mode makes it fail sooner. Mobile\n * therefore runs single-shot and is restarted from `onend` for as long as the visitor is\n * still dictating, which behaves like continuous without fighting the platform.\n */\n\ninterface SpeechRecognitionAlternativeLike {\n transcript: string;\n}\ninterface SpeechRecognitionResultLike {\n readonly isFinal: boolean;\n readonly length: number;\n [index: number]: SpeechRecognitionAlternativeLike;\n}\ninterface SpeechRecognitionEventLike {\n readonly resultIndex: number;\n readonly results: {\n readonly length: number;\n [index: number]: SpeechRecognitionResultLike;\n };\n}\ninterface SpeechRecognitionErrorEventLike {\n readonly error: string;\n}\ninterface SpeechRecognitionLike {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n start: () => void;\n stop: () => void;\n abort: () => void;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEventLike) => void) | null;\n onend: (() => void) | null;\n onstart: (() => void) | null;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionLike;\n\ninterface SpeechWindow {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n}\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === \"undefined\") return null;\n const w = window as unknown as SpeechWindow;\n return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\n/**\n * Coarse pointer means a touch device, which is what actually predicts the recogniser's\n * behaviour here — not the screen size, and not a UA string that lies.\n */\nfunction isTouchDevice(): boolean {\n if (typeof window === \"undefined\" || !window.matchMedia) return false;\n try {\n return window.matchMedia(\"(pointer: coarse)\").matches;\n } catch {\n return false;\n }\n}\n\nconst MIC_DENIED_MESSAGE =\n \"Microphone access was blocked. Allow it in your browser's site settings to dictate.\";\nconst MIC_UNAVAILABLE_MESSAGE =\n \"Dictation isn't available in this browser. You can type instead.\";\n\n/** Let a released capture settle before recognition opens its own. */\nconst RELEASE_SETTLE_MS = 250;\n/** Android often refuses the first start after a fresh grant and accepts the next. */\nconst RETRY_DELAY_MS = 350;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Ask for the microphone the only way that reliably raises a prompt on mobile.\n *\n * `confirmed` reports whether access was actually VERIFIED, which is what separates \"you need\n * to grant this\" from \"your browser cannot do this\" further down.\n *\n * Must be called synchronously from the user gesture that requested dictation — awaiting\n * anything first spends the gesture and the browser then rejects the request outright.\n */\nasync function ensureMicrophoneAccess(): Promise<\n | { ok: true; confirmed: boolean; primed: boolean }\n | { ok: false; message: string }\n> {\n const media =\n typeof navigator === \"undefined\" ? undefined : navigator.mediaDevices;\n // Older/unusual browsers without mediaDevices: fall through and let recognition try. It\n // may well work, and refusing here would remove dictation from browsers that support it.\n if (!media?.getUserMedia)\n return { ok: true, confirmed: false, primed: false };\n\n // `granted` means the prompt would not appear anyway, so skip the extra capture — which\n // also avoids the teardown race entirely on repeat use.\n //\n // A `denied` reading is deliberately NOT trusted to short-circuit. The Permissions API\n // reports `denied` for a prompt the visitor merely dismissed, and its microphone support\n // is uneven across mobile browsers — believing it would recreate the exact bug this\n // function exists to fix, telling someone to change a setting instead of asking them.\n // getUserMedia is the authoritative check, and when access really is denied it rejects\n // immediately without showing anything, so the only cost of asking is a settled promise.\n //\n // `permissions` is absent on Safari and `microphone` is not a valid name everywhere, so\n // every part of this is optional and failure is non-fatal.\n try {\n const status = await navigator.permissions?.query({\n name: \"microphone\" as PermissionName,\n });\n if (status?.state === \"granted\")\n return { ok: true, confirmed: true, primed: false };\n } catch {\n /* permissions API unavailable or the name is unsupported — prompt below instead */\n }\n\n try {\n const stream = await media.getUserMedia({ audio: true });\n // Release immediately: this capture existed only to raise the prompt, and leaving it\n // open would show a recording indicator for the whole session — and on mobile would\n // occupy the very microphone recognition is about to ask for.\n for (const track of stream.getTracks()) track.stop();\n return { ok: true, confirmed: true, primed: true };\n } catch (error) {\n const name =\n typeof error === \"object\" && error !== null && \"name\" in error\n ? String((error as { name: unknown }).name)\n : \"\";\n if (name === \"NotAllowedError\" || name === \"SecurityError\") {\n return { ok: false, message: MIC_DENIED_MESSAGE };\n }\n if (name === \"NotFoundError\" || name === \"DevicesNotFoundError\") {\n return { ok: false, message: \"No microphone was found.\" };\n }\n return {\n ok: false,\n message: \"Dictation could not start. You can type instead.\",\n };\n }\n}\n\n/** Messages a visitor can act on. `not-allowed` is the one that needs real explanation. */\nfunction describeError(code: string): string {\n switch (code) {\n case \"not-allowed\":\n case \"service-not-allowed\":\n return MIC_DENIED_MESSAGE;\n case \"no-speech\":\n return \"I didn't catch anything — try again a little closer to the mic.\";\n case \"audio-capture\":\n return \"No microphone was found.\";\n case \"network\":\n return \"Speech recognition needs a network connection.\";\n case \"aborted\":\n return \"\";\n default:\n return \"Dictation stopped unexpectedly. You can type instead.\";\n }\n}\n\nexport interface UseSpeechInputOptions {\n /** Receives settled text as it is recognised. Append it to the draft. */\n onFinalTranscript: (text: string) => void;\n /** BCP-47 tag. Defaults to the browser's language. */\n lang?: string;\n /** Called when the recogniser reports a problem worth showing. */\n onError?: (message: string) => void;\n}\n\nexport interface UseSpeechInputResult {\n /** False when the browser has no speech recogniser — hide the control entirely. */\n supported: boolean;\n listening: boolean;\n /** Words recognised but not yet settled; render as a live hint, do not store. */\n interim: string;\n error: string | null;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n}\n\nexport function useSpeechInput({\n onFinalTranscript,\n lang,\n onError,\n}: UseSpeechInputOptions): UseSpeechInputResult {\n const [supported] = useState(() => getRecognitionCtor() !== null);\n const [listening, setListening] = useState(false);\n const [interim, setInterim] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const recognitionRef = useRef<SpeechRecognitionLike | null>(null);\n /**\n * Bumped on every start()/stop(). A permission prompt, a settle delay or a retry resolving\n * after the visitor moved on must not open a microphone behind them.\n */\n const startTokenRef = useRef(0);\n /**\n * True only when the microphone was actually VERIFIED for this attempt — permission\n * reported granted, or getUserMedia succeeded. Stays false on browsers with no\n * mediaDevices, where nothing was checked and a recogniser `not-allowed` may still be a\n * real permission problem.\n */\n const micConfirmedRef = useRef(false);\n /** The visitor's intent, as opposed to whether a session happens to be open right now. */\n const wantsListeningRef = useRef(false);\n /** One retry per start(), for the Android \"refuses the first attempt\" case. */\n const retriedRef = useRef(false);\n\n // Held in refs so the recogniser's long-lived handlers always call the latest closures\n // without tearing down and re-creating the recogniser on every render.\n const finalRef = useRef(onFinalTranscript);\n const errorRef = useRef(onError);\n finalRef.current = onFinalTranscript;\n errorRef.current = onError;\n\n const langRef = useRef(lang);\n langRef.current = lang;\n\n const stop = useCallback(() => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n /** Open a recogniser session. Separate from start() so a retry can reuse it. */\n const openSession = useCallback((token: number) => {\n const Ctor = getRecognitionCtor();\n if (!Ctor || token !== startTokenRef.current) return;\n\n const recognition = new Ctor();\n recognition.lang =\n langRef.current ??\n (typeof navigator === \"undefined\"\n ? \"en-US\"\n : navigator.language || \"en-US\");\n // Continuous mode is a desktop-only affordance. Android Chrome ends the session after a\n // single utterance whatever this says, and asking for continuous makes it fail sooner —\n // mobile is restarted from `onend` instead, which behaves the same to the visitor.\n recognition.continuous = !isTouchDevice();\n recognition.interimResults = true;\n recognition.maxAlternatives = 1;\n\n recognition.onstart = () => {\n if (token !== startTokenRef.current) return;\n // NOTE: the retry budget is deliberately NOT reset here. It belongs to the visitor's\n // press, not to the session — a browser that fires onstart and then immediately\n // errors would otherwise retry forever.\n setError(null);\n setListening(true);\n };\n\n recognition.onresult = (event) => {\n if (token !== startTokenRef.current) return;\n let settled = \"\";\n let pending = \"\";\n for (let i = event.resultIndex; i < event.results.length; i += 1) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? \"\";\n if (result.isFinal) settled += text;\n else pending += text;\n }\n setInterim(pending);\n if (settled.trim() !== \"\") finalRef.current(settled);\n };\n\n recognition.onerror = (event) => {\n if (token !== startTokenRef.current) return;\n\n // Android commonly refuses the FIRST start after a permission is newly granted and\n // accepts the next one. Retry once, silently, before telling the visitor anything —\n // an error message they can do nothing about is worse than a short pause.\n if (\n (event.error === \"not-allowed\" ||\n event.error === \"service-not-allowed\") &&\n micConfirmedRef.current &&\n !retriedRef.current\n ) {\n retriedRef.current = true;\n void sleep(RETRY_DELAY_MS).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n\n // The microphone was verified moments ago, so a `not-allowed` that survived the retry\n // is the SPEECH SERVICE refusing, not a permission the visitor can grant. Sending them\n // to a site setting would point at something that cannot help.\n const message =\n micConfirmedRef.current &&\n (event.error === \"not-allowed\" || event.error === \"service-not-allowed\")\n ? MIC_UNAVAILABLE_MESSAGE\n : describeError(event.error);\n\n wantsListeningRef.current = false;\n setListening(false);\n setInterim(\"\");\n if (message !== \"\") {\n setError(message);\n errorRef.current?.(message);\n }\n };\n\n recognition.onend = () => {\n if (token !== startTokenRef.current) return;\n setInterim(\"\");\n // Single-shot mobile sessions end after each utterance. While the visitor still has\n // dictation switched on, reopen so it behaves like continuous mode.\n if (wantsListeningRef.current && isTouchDevice()) {\n void sleep(120).then(() => {\n if (token !== startTokenRef.current || !wantsListeningRef.current)\n return;\n openSessionRef.current?.(token);\n });\n return;\n }\n setListening(false);\n };\n\n recognitionRef.current = recognition;\n try {\n recognition.start();\n } catch {\n // Chrome throws InvalidStateError if start() races a session that is still closing.\n // The onend handler above will not fire for a session that never began, so settle here.\n wantsListeningRef.current = false;\n setListening(false);\n }\n }, []);\n\n // openSession refers to itself from its own handlers (retry, mobile restart), which a plain\n // const cannot do inside useCallback.\n const openSessionRef = useRef<((token: number) => void) | null>(null);\n openSessionRef.current = openSession;\n\n const start = useCallback(() => {\n if (!getRecognitionCtor()) return;\n\n startTokenRef.current += 1;\n const token = startTokenRef.current;\n wantsListeningRef.current = true;\n retriedRef.current = false;\n micConfirmedRef.current = false;\n\n // Show the pressed state straight away: the permission prompt can sit on screen for a\n // while on mobile, and a mic button that looks inert invites a second tap.\n setError(null);\n setListening(true);\n\n void ensureMicrophoneAccess().then(async (access) => {\n // A stop() or a newer start() landed while the prompt was open — abandon this attempt.\n if (token !== startTokenRef.current) return;\n\n if (!access.ok) {\n wantsListeningRef.current = false;\n setListening(false);\n setError(access.message);\n errorRef.current?.(access.message);\n return;\n }\n\n micConfirmedRef.current = access.confirmed;\n\n // Recognition opens its own capture. Starting in the same tick that the primed stream\n // is being torn down races that teardown and is refused — this is what made \"I granted\n // it and it still says blocked\" happen on mobile.\n if (access.primed) {\n await sleep(RELEASE_SETTLE_MS);\n if (token !== startTokenRef.current) return;\n }\n\n openSessionRef.current?.(token);\n });\n }, []);\n\n const toggle = useCallback(() => {\n if (listening) stop();\n else start();\n }, [listening, start, stop]);\n\n // Never leave the microphone open behind a closed page.\n useEffect(\n () => () => {\n startTokenRef.current += 1;\n wantsListeningRef.current = false;\n const recognition = recognitionRef.current;\n if (!recognition) return;\n recognition.onresult = null;\n recognition.onerror = null;\n recognition.onend = null;\n recognition.onstart = null;\n try {\n recognition.abort();\n } catch {\n /* nothing to abort */\n }\n },\n [],\n );\n\n return { supported, listening, interim, error, start, stop, toggle };\n}\n"]}
|