{"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-AJPGQCZ2.cjs","../src/contexts/endpoints-runtime-context.tsx","../src/contexts/chat-runtime-context.tsx"],"names":["createContext","useContext"],"mappings":"AAAA,qFAAY;AACZ;AACA;ACqBA,8BAA0C;AAqBnC,IAAM,wBAAA,EAA0B,kCAAA,IAA2C,CAAA;AAO3E,SAAS,mBAAA,CAAA,EAA+C;AAC7D,EAAA,OAAO,+BAAA,uBAAkC,CAAA;AAC3C;AASO,SAAS,2BAAA,CAAA,EAAgD;AAC9D,EAAA,MAAM,EAAA,EAAI,+BAAA,uBAAkC,CAAA;AAC5C,EAAA,GAAA,CAAI,CAAC,CAAA,EAAG;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,IAIF,CAAA;AAAA,EACF;AACA,EAAA,OAAO,CAAA;AACT;ADxDA;AACA;AEiBA;AAoOO,IAAM,mBAAA,EAAqBA,kCAAAA,IAAsC,CAAA;AAQjE,SAAS,cAAA,CAAA,EAAqC;AACnD,EAAA,OAAOC,+BAAAA,kBAA6B,CAAA;AACtC;AAUO,SAAS,sBAAA,CAAA,EAAsC;AACpD,EAAA,MAAM,EAAA,EAAIA,+BAAAA,kBAA6B,CAAA;AACvC,EAAA,GAAA,CAAI,CAAC,CAAA,EAAG;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,IAMF,CAAA;AAAA,EACF;AACA,EAAA,OAAO,CAAA;AACT;AFvQA;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACF,mUAAC","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-AJPGQCZ2.cjs","sourcesContent":[null,"'use client'\n\n/**\n * Endpoints runtime — sibling of ChatRuntime. Carries the API path\n * literals consumed by oss-lib components/hooks/utils so a host\n * application can override them (e.g. when running behind a reverse\n * proxy as `user1.openframe.ai` → `/api/mingo-guide/*`).\n *\n * The hub mounts `<HubRuntimeProvider>` at root with the\n * canonical hub paths; an embedded app mounts its own provider with\n * remapped paths. The pattern mirrors ChatRuntimeContext exactly:\n *\n *   - `useEndpointsRuntime()` returns null when no provider is mounted.\n *     For optional consumers that should gracefully no-op without one.\n *   - `useRequiredEndpointsRuntime()` throws on missing provider — for\n *     hooks/components that cannot function without endpoints.\n *\n * IMPORTANT for embedders: memoize the value passed to\n * `<EndpointsRuntimeContext.Provider value={...}>` (e.g. React.useMemo).\n * Reference changes invalidate downstream effect dependency arrays and\n * trigger unnecessary re-fetches.\n */\n\nimport { createContext, useContext } from 'react'\n\nexport interface EndpointsRuntime {\n  /** GET active announcement (used by `<AnnouncementBar>` mount fetch + refocus revalidation). */\n  announcementsUrl: string\n  accessCode: {\n    /** POST validate access code. */\n    validateUrl: string\n    /** POST consume / redeem access code after registration. */\n    consumeUrl: string\n  }\n  /** POST contact-form submission. */\n  contactUrl: string\n  /** GET base of the host's private-storage view proxy\n   *  (`<base>/<bucket>/<object>`). `ClaudeEmbed` derives artifact mirror\n   *  urls under it (`<base>/design-briefs/<uuid>.html`). OPTIONAL: a host\n   *  without the proxy simply omits it and claude embeds fall back to\n   *  claude.ai — no probing happens. */\n  storageViewBaseUrl?: string\n}\n\nexport const EndpointsRuntimeContext = createContext<EndpointsRuntime | null>(null)\n\n/**\n * Optional read — returns null when no provider is mounted. Use for\n * surfaces that should silently skip the fetch (e.g. announcement\n * polling on a page rendered outside the provider tree).\n */\nexport function useEndpointsRuntime(): EndpointsRuntime | null {\n  return useContext(EndpointsRuntimeContext)\n}\n\n/**\n * Strict variant — throws on missing provider. Use for consumers that\n * cannot function without an endpoint (form submission, code\n * validation). In tests/Storybook, wrap with the hub's\n * `<HubRuntimeProvider>` or a stub\n * `<EndpointsRuntimeContext.Provider value={mockedEndpoints}>`.\n */\nexport function useRequiredEndpointsRuntime(): EndpointsRuntime {\n  const v = useContext(EndpointsRuntimeContext)\n  if (!v) {\n    throw new Error(\n      '[endpoints-runtime] hook called outside an <EndpointsRuntimeContext.Provider>. ' +\n        'Hub: mount <HubRuntimeProvider> in your providers tree. ' +\n        'Embedded app: mount your own provider with proxied URLs at the tree root. ' +\n        'Tests/Storybook: wrap render() in <EndpointsRuntimeContext.Provider value={mocked}>.',\n    )\n  }\n  return v\n}\n","'use client'\n\n/**\n * Chat runtime context — single seam for embedding the chat panel in a\n * different host (e.g. user1.openframe.ai reverse-proxying API calls\n * under /api/mingo-guide/* to hub.openframe.ai/api/*).\n *\n * Three concerns, one context:\n *   1. API endpoints: chatStreamUrl / approvalToolUrl / commandsUrl /\n *      buildListUrl + attachment endpoints + chat-identity. The chat\n *      reads them from runtime; hub vs embedded app supply different\n *      strings via different providers.\n *   2. Navigation mode + callbacks: 'host' or 'embed' mode. Host wires\n *      its own router/docNav via the optional `navigate` callback\n *      (plain function, NOT a hook); embed forces new-tab via\n *      `defaultContentOrigin` + lib's `resolveExternalNavigation`.\n *   3. Identity context: only `source` (required for localStorage\n *      namespacing). The display identity (greeting first-name etc.)\n *      comes from the server via `useChatIdentity()` — never injected\n *      client-side, so it always matches the server-resolved auth.\n *\n * Sibling of EndpointsRuntimeContext (announcement bar, contact form,\n * access codes). Each runtime stays an independent React context so\n * embedders can opt into either feature without forcing the other.\n *\n * IMPORTANT for embedders: memoize the value passed to\n * `<ChatRuntimeContext.Provider value={...}>` (e.g. via React.useMemo).\n * Every change to its reference identity invalidates downstream\n * `useMemo` consumers (the chat input's slash-commands binding,\n * useNavLink's embed-resolution memo, useDocChat's streamFn factory).\n * The hub's `<HubRuntimeProvider>` already memoizes correctly with\n * stable deps. Embedded apps that build the value inline on each render\n * will pay an avoidable re-render cost across the entire chat tree.\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\n\nimport type { ComposeContentUrl } from '../utils/content-href'\n\n/**\n * Runtime config consumed by the chat panel.\n */\nexport interface ChatRuntime {\n  endpoints: {\n    /** POST streaming chat. Hub: '/api/docs/chat'. */\n    chatStreamUrl: string\n    /** POST agent approve/reject. Hub: '/api/chat/agent/confirm-tool'. */\n    approvalToolUrl: string\n    /** Customer-ticket agent endpoints (Help Center). OPTIONAL — when unset,\n     *  the ticket hooks fall back to the bare hub paths\n     *  (`/api/chat/agent/{find-ticket,ticket-action,list-engagements}`).\n     *  Embedders behind a reverse proxy set these to their proxied paths\n     *  (e.g. `/content/api/chat/agent/...`) so tickets route through the SAME\n     *  endpoint config + proxy as every other endpoint. */\n    findTicketUrl?: string\n    ticketActionUrl?: string\n    listEngagementsUrl?: string\n    /** Ticket live-stream + read-receipt endpoints (Help Center\n     *  realtime). OPTIONAL — unset → bare hub paths under the DEDICATED\n     *  ticket surface (`/api/tickets/{stream,read}` — deliberately NOT\n     *  the chat agent's `/api/chat/agent/*` prefix). Reverse-proxy\n     *  embedders set their proxied paths. Consumed by\n     *  `TicketLiveProvider`. The unread summary has NO endpoint — it\n     *  arrives as `ticket-summary` frames on the stream and in\n     *  `ticket-read` responses. */\n    ticketStreamUrl?: string\n    ticketReadUrl?: string\n    /** GET slash-command catalog. Hub: '/api/docs/commands'. */\n    commandsUrl: string\n    /** GET server-side conversation history (`?conversationId=<id>`) — the\n     *  chat panel's mount-time hydration read against the server transcript\n     *  store (localStorage keeps only the server-issued conversation id).\n     *  OPTIONAL — defaults to `<chatStreamUrl>/history`, which is correct for\n     *  same-origin hosts AND for reverse-proxy embedders (the proxied chat\n     *  prefix covers it). Set explicitly only when the history route lives\n     *  elsewhere. */\n    chatHistoryUrl?: string\n    /** GET RAG-search endpoint behind `<DocSearchBar>` (the in-source search\n     *  bar mounted by `<DocViewer>` / `<DocsHubPage>` when `showAIChat` is on).\n     *  Hub: '/api/docs/search'. OPTIONAL — falls back to the hub path so\n     *  same-origin Next.js hosts don't need to set it. Cross-origin embedders\n     *  set their proxied path so the search bar routes through the same\n     *  reverse proxy as everything else. Same pattern as `findTicketUrl`. */\n    docsSearchUrl?: string\n    /** POST internal-link resolver. The in-source markdown renderer (lib or\n     *  custom) calls `<DocViewer>`'s `handlers.onResolveLink(href, currentPath)`\n     *  for relative hrefs like `./getting-started/intro.md` — that callback\n     *  posts to this URL with `{ link, currentPath, source }` and expects a\n     *  `ResolveLinkResult` back. Hub: '/api/docs/resolve-link'. OPTIONAL — same\n     *  fall-back chain as `docsSearchUrl`: prop override → runtime → default. */\n    docsResolveLinkUrl?: string\n    /** GET per-platform empty-state config (admin-edited in\n     *  `/admin/chat-config`): `{ greeting, enabledRagTableIds, suggestedQueries }`.\n     *  Hub: '/api/docs/empty-state'. OPTIONAL — the in-app (host-mode) chat\n     *  injects these values as SSR props instead, so it leaves this unset.\n     *  Cross-origin EMBEDDERS (no server hop) set it to their proxied path\n     *  (e.g. '/content/api/docs/empty-state') so `<EmbeddableChat>` can fetch\n     *  the greeting / quick-action chips / RAG-source filter at runtime. When\n     *  unset, the chat falls back to the explicit `emptyStateGreeting` /\n     *  `suggestedQueries` / `enabledRagTableIds` props (or in-code defaults). */\n    emptyStateUrl?: string\n    /** Build the per-agent display-config URL for an OpenFrame AI agent\n     *  (Fae/Mingo). OPTIONAL. The returned endpoint MUST be byte-compatible\n     *  with the empty-state wire shape ({ greeting, suggestedQueries,\n     *  enabledRagTableIds }). When set AND `EmbeddableChat` receives an\n     *  `activeAgentSlug` in embed mode, the chat fetches THIS url instead of\n     *  `emptyStateUrl` to render the selected agent's greeting + suggested\n     *  prompts (the \"agent mode\" URL override). Hub: `(slug) =>\n     *  '/api/ai-agents/' + encodeURIComponent(slug)`. */\n    aiAgentConfigUrl?: (slug: string) => string\n    /** Build entity-card list URL for a content type + ids. Hub delegates\n     *  to the rag-table-config registry; embedded app provides its own\n     *  per-type URL builder against the reverse proxy. Returns null when\n     *  the type has no list endpoint (caller skips rendering). */\n    buildListUrl: (type: string, ids: string[]) => string | null\n    /** Chat-attachment endpoints — added for the v2 attachment feature.\n     *\n     *  Three concerns:\n     *    - `attachmentUploadUrl` — POSTed by the chat-attachment hook\n     *      to mint a Supabase signed-upload-URL + HMAC view token.\n     *    - `attachmentViewUrlPrefix` — embedded in markdown URLs the\n     *      chat hosts in user message bubbles (`![]()` / `[Attached]`).\n     *      Stored in chat history; chosen at SEND time. In host mode the\n     *      relative `/api/storage/view/chat-attachments/` is sufficient\n     *      (same-origin); embedders supply an absolute hub URL so the\n     *      browser can fetch cross-origin.\n     *    - `identityUrl` — GET endpoint the `useChatIdentity` hook\n     *      hits to learn the `{authTier, source, attachmentsEnabled}`\n     *      capability bag for the current session. Used beyond chat\n     *      (tickets / contact form / any embedded surface that needs\n     *      to identify the proxied customer), so the name has no\n     *      \"chat\" prefix even though the consuming hook still does. */\n    attachmentUploadUrl: string\n    attachmentViewUrlPrefix: string\n    identityUrl: string\n    /** Optional URL prefix for the image proxy (`<prefix>?url=<external>`).\n     *  When unset, lib's `getProxiedImageUrl` returns the original URL\n     *  unchanged. Hub default: '/api/image-proxy'. Embedders that don't\n     *  host an image-proxy route leave this undefined → images load\n     *  directly cross-origin (CORS-permitting). */\n    imageProxyUrlPrefix?: string\n    /** Optional list of hostnames that should bypass the image proxy\n     *  (rendered direct). Hub uses ['openmsp.ai']; embedders typically\n     *  leave it unset. Matches the `skipDomains` parameter of\n     *  `getProxiedImageUrl`. */\n    imageProxySkipDomains?: string[]\n    /** Optional base URL for the branded og-placeholder image route — the\n     *  DEFAULT cover-image fallback for entity cards with no image. The lib\n     *  appends `?title=…` (+ `w`/`h` for square slots) itself, so this is\n     *  the base, NOT a full URL: relative (`/api/og-placeholder`) for same-\n     *  origin hosts, or the proxied path (`/content/api/og-placeholder`) for\n     *  cross-origin embedders. May carry baked-in query params (preserved when\n     *  the lib layers `title`/dimensions on top) — but per-platform brand\n     *  colors are NO LONGER baked here; the `/api/og-placeholder` route\n     *  resolves them server-side from the platform. Most hosts leave this unset\n     *  and let the lib derive the base from `imageProxyUrlPrefix`.\n     *\n     *  OPTIONAL — when unset the lib derives the base from the sibling\n     *  `imageProxyUrlPrefix` (same API base, route name swapped), then falls\n     *  back to the relative `/api/og-placeholder`. So an embedder that already\n     *  proxies images needs NO og-placeholder wiring. See\n     *  `resolveOgPlaceholderBase` / `buildOgPlaceholderUrl` in `../utils`. */\n    ogPlaceholderUrl?: string\n    /** Base URL prefix for the captions route (`/api/captions` — the native\n     *  `<track>` VTT endpoint every video surface uses since captions stopped\n     *  being burned into video pixels). Plain path base, no query params.\n     *  Embedders point it at their proxied route (e.g. `/content/api/captions`);\n     *  unset ⇒ the same-origin relative `/api/captions` (the hub). Consumed via\n     *  `getEntityCaptionUrls` / `rebaseCaptionsUrl` in\n     *  `components/features/captions-url.ts`. */\n    captionsUrlPrefix?: string\n    /** Supabase storage origin (e.g. `https://xyz.supabase.co`) — used\n     *  by `useVideoWarmup` to scope the `<link rel=\"preload\" as=\"video\">`\n     *  hint to MP4s the deployment actually hosts. Hub wires it via\n     *  `getSupabaseStorageOrigin()`; embedders without a Supabase\n     *  storage origin leave it unset (preload is then skipped; Mux/\n     *  YouTube preconnect still fires). */\n    supabaseStorageOrigin?: string\n  }\n  navigation: {\n    /** ONE knob, two behaviors:\n     *  - 'host' = use the host page's existing click-routing untouched.\n     *    The chat panel calls `navigate?.()` for in-app routing.\n     *  - 'embed' = guest inside another app: short-circuit at the top\n     *    of click handlers to force new-tab + absolutize via\n     *    resolveExternalNavigation. */\n    mode: 'host' | 'embed'\n    /** Embed-only fallback origin for relative URLs whose target platform\n     *  can't be inferred. Used by resolveExternalNavigation when\n     *  `targetPlatform` is null — without this, a relative `/foo` href would\n     *  window.open against the embedder's origin, which is WRONG.\n     *  Set to your content host (e.g. 'https://hub.openframe.ai').\n     *  Required by the embedded app whenever mode='embed'. */\n    defaultContentOrigin?: string\n    /** Override for opening external URLs. MUST BE SYNCHRONOUS —\n     *  Safari/Firefox block popups opened outside a direct user gesture.\n     *  Default: window.open(href, '_blank', 'noopener,noreferrer'). */\n    openExternal?: (href: string) => void\n    /** Optional in-app navigation callback (host-mode only).\n     *  Returns `true` if the host handled the click in-app\n     *  (router.push + docNav.navigate); returns `false`, `undefined`,\n     *  or `void` → lib falls back to window.location.assign(href).\n     *  Hub wires this via HubRuntimeProvider's HubNavigationWiring;\n     *  embedders not in Next.js leave it undefined. */\n    navigate?: (input: { href: string; path?: string | null; targetPlatform?: string | null }) => boolean | void\n    /** Optional new-tab decision callback. Returns true → lib opens in\n     *  new tab; false → same tab via `navigate`. Hub wires the existing\n     *  `decideNewTab` logic from use-nav-link.tsx (re-imports the pure\n     *  helper from lib). Embedders may omit; lib defaults to:\n     *  same-origin/same-platform → same tab, else new tab. */\n    decideNewTab?: (args: { href: string; targetPlatform?: string | null }) => boolean\n  }\n  /** Optional content-URL composer. Returns the platform-aware href +\n   *  target-platform tuple for a content entity. Hub wires this to its\n   *  `buildContentURL(type, slug, extractPrimaryPlatform(platforms))`\n   *  pipeline so the lib catalog/detail views can derive cross-\n   *  platform hrefs without knowing the hub's platform topology\n   *  (openmsp.ai / openframe.app / flamingo.run / tmcg).\n   *\n   *  THE single content-href authority for every embeddable surface — page\n   *  views (onboarding catalog/detail, releases) AND chat cards / chips /\n   *  search results all resolve content links through this one seam, so a\n   *  given type lands in the SAME place regardless of where it's rendered.\n   *  Embedders wire `makeComposeContentUrl({ hostedTypes, contentOrigin })`;\n   *  omit it and lib views fall back to a same-origin relative path\n   *  (`buildDefaultHref`).\n   *\n   *  Takes a single `ComposeContentUrlInput`: `type` + `identifier` (page\n   *  views pass the slug; chat rows pass the id + `externalUrl`, whose path\n   *  yields the slug for in-app routing) + optional `platforms` /\n   *  `externalUrl` / `targetPlatform`. */\n  composeContentUrl?: ComposeContentUrl\n  /** Per-`documentType` doc-viewer targets — the UNIFIED, DYNAMIC replacement for\n   *  the single `chipBasePlatform` prop. Maps a doc-table documentType\n   *  (`'markdown'`, `'data_room_doc'`, …) → `{ platform, basePath }` for the PUBLIC\n   *  doc viewer that hosts it. Doc chips with no `externalUrl` resolve PER ROW to\n   *  `getBaseUrl(platform)/<basePath>/<path>`, so a chat mixing several doc sources\n   *  sends EACH to its own home (markdown→flamingo/knowledge-base,\n   *  data_room_doc→company-hub/data-room) instead of one static fallback. The hub\n   *  may keep using `chipBasePlatform` (one doc source per platform); embedders that\n   *  surface multiple doc sources wire this. Threaded into `resolveSourceRowCTA`. */\n  docPlatformTargets?: Record<string, { platform: string; basePath: string }>\n  /** Chat source / platform identifier — OPTIONAL. The hub sets it from\n   *  `currentPlatform()`; EMBEDDERS leave it unset and stay platform-agnostic.\n   *\n   *  It is NOT required for chat to work. The wire resolves source server-side\n   *  (`/docs/chat|search|commands` reject any client `source`); the\n   *  same-tab-vs-new-tab link decision falls back to an origin comparison when\n   *  it's absent (`decideNewTab` → `isCrossOriginUrl`); and the localStorage\n   *  history namespace falls back to a stable constant. Set it only where the\n   *  client legitimately needs to know its platform a priori — i.e. the hub,\n   *  where several platforms share related origins so \"same platform\" can't be\n   *  inferred from a URL alone. */\n  source?: string\n  // NOTE: No `user` field. The chat's display identity (greeting\n  // first-name, etc.) comes from the SERVER-resolved auth via\n  // `useChatIdentity()` — the same identity the server uses to\n  // authorize requests. Letting embedders pass a client-side `user`\n  // would let it desync from the actual auth tier, causing greetings\n  // like \"Hey Bob\" while the server treats the session as\n  // alice@example.com. Single source of truth: the server.\n}\n\nexport const ChatRuntimeContext = createContext<ChatRuntime | null>(null)\n\n/**\n * Returns the active runtime, or null when no provider is mounted.\n * NULL is a first-class value — it signals \"no chat runtime configured.\"\n * Optional consumers fall back to no-op behavior; strict consumers\n * use `useRequiredChatRuntime` (below).\n */\nexport function useChatRuntime(): ChatRuntime | null {\n  return useContext(ChatRuntimeContext)\n}\n\n/**\n * Strict variant used INSIDE the chat panel. Throws if no provider.\n * The hub guarantees one exists by mounting `<HubRuntimeProvider>` at\n * root; the embedded app mounts its own `<ChatRuntimeContext.Provider>`\n * at the tree root. In Jest / Storybook tests that render chat\n * internals directly, wrap with `<HubRuntimeProvider>` (hub defaults)\n * or supply `<ChatRuntimeContext.Provider value={mockedRuntime}>`.\n */\nexport function useRequiredChatRuntime(): ChatRuntime {\n  const v = useContext(ChatRuntimeContext)\n  if (!v) {\n    throw new Error(\n      '[chat-runtime] hook called outside a <ChatRuntimeContext.Provider>. ' +\n        'The hub mounts <HubRuntimeProvider> at root — this only fires when ' +\n        'chat internals are rendered above the provider tree. ' +\n        'Fix: ensure the rendering subtree descends from the runtime provider. ' +\n        'In tests/Storybook: wrap with <HubRuntimeProvider> or supply ' +\n        'a <ChatRuntimeContext.Provider value={mockedRuntime}>.',\n    )\n  }\n  return v\n}\n"]}