@matterfact/embed 0.3.0 → 0.4.0
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/README.md +20 -0
- package/dist/{chunk-33LPVL2R.js → chunk-523BCS2Z.js} +3 -3
- package/dist/{chunk-33LPVL2R.js.map → chunk-523BCS2Z.js.map} +3 -3
- package/dist/{chunk-SQJX27LT.js → chunk-SBNMM3ZV.js} +85 -28
- package/dist/chunk-SBNMM3ZV.js.map +1 -0
- package/dist/chunk-URIBHOOQ.js +2 -0
- package/dist/chunk-XLQ36ZMV.js +2 -0
- package/dist/chunk-XLQ36ZMV.js.map +7 -0
- package/dist/{chunk-CHPADW72.js → chunk-Z4WT3TIZ.js} +86 -30
- package/dist/chunk-Z4WT3TIZ.js.map +1 -0
- package/dist/{context-MORDASRH.js → context-432WQST4.js} +6 -4
- package/dist/context-KZAUOIR6.js +3 -0
- package/dist/{context-BFNFFHC2.js.map → context-KZAUOIR6.js.map} +1 -1
- package/dist/embed.js +1 -1
- package/dist/embed.js.map +3 -3
- package/dist/index.cjs +100 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +102 -34
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +14 -1
- package/dist/react.d.ts +14 -1
- package/dist/react.js +13 -6
- package/dist/react.js.map +1 -1
- package/dist/{snapshot-QBV7DTJP.js → snapshot-Q3CALMHD.js} +7 -4
- package/dist/snapshot-Q3CALMHD.js.map +1 -0
- package/dist/{snapshot-IWVXLE4G.js → snapshot-SOMSG2OF.js} +6 -2
- package/dist/snapshot-SOMSG2OF.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-CHPADW72.js.map +0 -1
- package/dist/chunk-F7DLOR7F.js +0 -2
- package/dist/chunk-F7DLOR7F.js.map +0 -7
- package/dist/chunk-FBIJZJGL.js +0 -2
- package/dist/chunk-SQJX27LT.js.map +0 -1
- package/dist/context-BFNFFHC2.js +0 -3
- package/dist/snapshot-IWVXLE4G.js.map +0 -1
- package/dist/snapshot-QBV7DTJP.js.map +0 -1
- /package/dist/{chunk-FBIJZJGL.js.map → chunk-URIBHOOQ.js.map} +0 -0
- /package/dist/{context-MORDASRH.js.map → context-432WQST4.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts"],"names":[],"mappings":"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","file":"chunk-Z4WT3TIZ.js","sourcesContent":["import type {\n ActivityEvent,\n FocusContext,\n HostToWidget,\n PageContext,\n PageEntity,\n ToolCall,\n} from './protocol';\n\n/** The origin serving our chat — how we tell OUR embedded content from the host's own\n * iframes. Set by start(); empty until then, which just means we spot nothing. */\nlet widgetOrigin = '';\n\n/**\n * The eye.\n *\n * Everything in this module can see the customer's page. It is a SEPARATE CHUNK,\n * loaded only when someone actually opens the chat — so a page whose visitors never\n * click the widget pays nothing for any of it, and a security reviewer can read\n * exactly one file to know what we look at.\n *\n * The rules, which are not negotiable:\n *\n * NEVER captured — no config enables it: the value of any <input>, <textarea> or\n * contenteditable; anything inside a password field; cookies; localStorage;\n * sessionStorage; the raw DOM; screenshots; network traffic; anything inside an\n * element marked `data-mf-private`.\n *\n * The agent never gets a selector and never touches the DOM. It gets refs. A ref\n * is resolved to an element HERE, in the page, by us.\n */\n\ntype Send = (msg: HostToWidget) => void;\n\nconst MAX_ACTIVITY = 40;\n\nlet send: Send | null = null;\nlet activitySeq = 0;\nconst activity: ActivityEvent[] = [];\nlet lastUrl = '';\n/** Set once by `start()`. False ⇒ the host opted out of ALL page observation — every\n * exported entry point below that would otherwise read or send the page checks this. */\nlet pageContextOn = true;\n\n/* ─────────────────────────── teardown state ───────────────────────────── */\n\n/**\n * Everything below is module-global bookkeeping so `stop()` (see `start()`, bottom of\n * file) can undo exactly what `start()`/`watchNavigation()`/`beginAuth()` installed —\n * remove every listener, restore `history` to what it was before we wrapped it, and\n * forget any DOM-walk module we pulled in. All of this outlives a single `EmbedHost`;\n * see `stop()`'s doc comment for why that's the bug this exists to close.\n */\n\n/** The `fire` closure `watchNavigation()` handed to `popstate` — the only handle we\n * have to remove that listener again. */\nlet navFire: (() => void) | null = null;\n/** The `history.pushState`/`replaceState` this module wrapped, captured so `stop()`\n * can restore them EXACTLY rather than re-wrapping (which is how the old code\n * double-fired navigation on a second `start()`). */\nlet origPushState: History['pushState'] | null = null;\nlet origReplaceState: History['replaceState'] | null = null;\n/** The `message` listener `beginAuth()` is currently waiting on, if any. */\nlet pendingAuthListener: ((event: MessageEvent) => void) | null = null;\n/** Set once `sendSnapshot`/`sendRegion`/`readFocus` actually pull in the DOM-walk\n * chunk (`./dom/snapshot`) — never imported eagerly, so `stop()` doesn't pay for a\n * chunk that a host who only ever opted out (and never opened a snapshot) never\n * loaded in the first place. */\nlet snapshotModule: { clearRefs: () => void } | null = null;\n\n/* ─────────────────────────── redaction ────────────────────────────────── */\n\nconst PII = [\n /\\b[\\w.+-]+@[\\w-]+\\.[\\w.]{2,}\\b/g, // email\n /\\b(?:\\d[ -]?){13,19}\\b/g, // card-ish\n /\\b\\d{3}[- ]?\\d{2}[- ]?\\d{4}\\b/g, // ssn — dashed, spaced, OR bare 9 digits\n /\\b\\d{9,}\\b/g, // long bare digit runs: account / MRN / routing numbers\n /(?:\\+?\\d{1,2}[\\s.-]?)?\\(?\\d{3}\\)?[\\s.-]\\d{3}[\\s.-]\\d{4}\\b/g, // us phone\n /\\b(?:sk|pk|rk|ak)_(?:live|test)_[A-Za-z0-9]{8,}\\b/g, // stripe-style api keys\n /\\beyJ[\\w-]+\\.[\\w-]+\\.[\\w-]+\\b/g, // jwt\n];\n\n/**\n * Scrub before anything leaves the page — not after it arrives.\n *\n * A compromised widget, or a bug in ours, must not be able to retroactively obtain\n * a customer's users' email addresses. The only way to guarantee that is to never\n * put them on the wire.\n */\nexport function redact(text: string): string {\n let out = text;\n for (const re of PII) out = out.replace(re, '[redacted]');\n return out;\n}\n\n/** Anything the host has marked private, or that is inherently sensitive, is out. */\nexport function isPrivate(el: Element): boolean {\n if (el.closest('[data-mf-private]')) return true;\n const tag = el.tagName;\n if (tag === 'INPUT') {\n const t = (el as HTMLInputElement).type;\n if (t === 'password' || t === 'hidden') return true;\n }\n return false;\n}\n\n/* ───────────────────────── page context ───────────────────────────────── */\n\n/**\n * What the page says about itself.\n *\n * A host that declares nothing still gets URL + title, which is what every other\n * embeddable assistant on the market offers in total. The interesting fields\n * (`route`, `description`, `entities`) are host-declared, because only the host\n * knows that `/o/8813` is \"the Acme Corp order, 3 items, unpaid\".\n *\n * Declared via a global the host sets before we load:\n * window.matterfact = { context: { route: '/orders/:id', description: '...', entities: [...] } }\n */\n/**\n * matterfact content embedded IN the host page — today, artifact iframes.\n *\n * A cross-origin iframe is opaque: `contentDocument` throws, so the DOM snapshot walks\n * straight past an embedded artifact and the agent is blind to the very thing the page\n * is built around. It reads the page as empty and asks which URL you mean.\n *\n * We don't need to see inside, and shouldn't want to. The artifact's ID is right there\n * in the src, and the agent can already resolve `artifacts/<id>/` in its session — the\n * same path an `@`-mention uses. So we report the ID and let the backend fetch the real\n * thing, which beats scraping a rendering of it: it gets the data, not the picture.\n *\n * Matched by ORIGIN, not by path shape: a customer is perfectly entitled to their own\n * /artifacts/ route, and it isn't ours.\n */\n/** The artifact slug from a matterfact artifact path, or null. Matches both the\n * chrome-free embed route (/embed/artifacts/<slug>) and the bare /artifacts/<slug>. */\nexport function artifactIdFromPath(pathname: string): string | null {\n const m = pathname.match(/^\\/(?:embed\\/)?artifacts\\/(.+?)\\/?$/);\n return m ? decodeURIComponent(m[1]) : null;\n}\n\nfunction embeddedMatterfactEntities(): PageEntity[] {\n if (!widgetOrigin) return [];\n const out: PageEntity[] = [];\n for (const frame of Array.from(document.querySelectorAll('iframe'))) {\n let u: URL;\n try {\n u = new URL(frame.getAttribute('src') || '', location.href);\n } catch {\n continue;\n }\n if (u.origin !== widgetOrigin) continue;\n const id = artifactIdFromPath(u.pathname);\n if (!id) continue;\n if (out.some((e) => e.id === id)) continue; // same artifact twice = once\n // No url field: the agent reaches an artifact by ID (`artifacts/<id>/`), never by\n // fetching the page, and an artifact URL can carry a share token we've no business\n // forwarding. The id is the whole useful payload.\n out.push({\n kind: 'artifact',\n id,\n label: redact(frame.getAttribute('title') || '') || id,\n });\n }\n return out;\n}\n\n/**\n * Frames we can see the existence of but nothing inside — someone else's cross-origin\n * embed. Worth one line: \"there is a thing here I cannot read\" is a true and useful\n * statement, and much better than the agent confidently describing a page while missing\n * the widget the user is actually asking about.\n */\nfunction opaqueFrameCount(): number {\n return Array.from(document.querySelectorAll('iframe')).filter((f) => {\n try {\n const u = new URL(f.getAttribute('src') || '', location.href);\n return u.origin !== location.origin && u.origin !== widgetOrigin;\n } catch {\n return false;\n }\n }).length;\n}\n\nexport function readPageContext(): PageContext {\n const declared =\n (window as { matterfact?: { context?: PageContext } }).matterfact\n ?.context ?? {};\n\n const found = embeddedMatterfactEntities();\n const opaque = opaqueFrameCount();\n\n return {\n // Path only. A query string is where session ids, tokens and email addresses\n // live; it is not ours to take.\n url: location.origin + location.pathname,\n path: location.pathname,\n title: redact(document.title),\n locale: document.documentElement.lang || undefined,\n ...declared,\n // After the spread: what we FOUND is additive to what the host DECLARED, never a\n // replacement. A host that declares its own entities still gets the artifacts we\n // spotted, and vice versa.\n entities: [...(declared.entities ?? []), ...found],\n data: {\n ...(declared.data ?? {}),\n ...(opaque ? { opaque_frames: opaque } : {}),\n },\n };\n}\n\nfunction publishContext() {\n send?.({ type: 'host.context', context: readPageContext() });\n}\n\n/* ─────────────────────── artifact grants (backend-only) ────────────────── */\n\nexport interface ArtifactGrantSrc {\n id: string;\n owner: string;\n token: string;\n}\n\n/** Read-only capability grants from co-embedded artifact iframes, for the backend to\n * materialize their data. Separate from entities on purpose: the token must never ride\n * ambient (rendered) context, only this backend-only channel. */\nexport function grantsFromIframeSrcs(\n srcs: string[],\n origin: string,\n): ArtifactGrantSrc[] {\n const out: ArtifactGrantSrc[] = [];\n for (const raw of srcs) {\n let u: URL;\n try {\n u = new URL(raw || '', location.href);\n } catch {\n continue;\n }\n if (u.origin !== origin) continue;\n const id = artifactIdFromPath(u.pathname);\n if (!id) continue;\n const owner = u.searchParams.get('owner') || '';\n const token = u.searchParams.get('t') || '';\n if (!owner || !token) continue;\n if (out.some((g) => g.id === id)) continue;\n out.push({ id, owner, token });\n }\n return out;\n}\n\nfunction readArtifactGrants(): ArtifactGrantSrc[] {\n if (!widgetOrigin) return [];\n const srcs = Array.from(document.querySelectorAll('iframe')).map(\n (f) => f.getAttribute('src') || '',\n );\n return grantsFromIframeSrcs(srcs, widgetOrigin);\n}\n\nfunction publishArtifactGrants() {\n send?.({ type: 'host.artifactGrants', grants: readArtifactGrants() });\n}\n\n/* ────────────────────────── activity ──────────────────────────────────── */\n\nfunction pushActivity(e: Omit<ActivityEvent, 'seq' | 'ts'>) {\n activity.push({ ...e, seq: ++activitySeq, ts: Date.now() });\n if (activity.length > MAX_ACTIVITY) activity.shift();\n send?.({ type: 'host.activity', events: [activity[activity.length - 1]] });\n}\n\n/**\n * A short, human-readable label for what got clicked.\n *\n * Shaped after PostHog's autocapture, not after a session-replay frame: rrweb would\n * give us `{source:2, type:2, id:417, x:210, y:88}` — no text, no role, no href,\n * meaningless to a model without the full DOM snapshot it deltas against. One line\n * of \"clicked button 'Export CSV'\" is worth more and costs less.\n */\n/**\n * The accessible NAME of a form control — never its value.\n *\n * A control has no `innerText`, so the generic path below misses it. We look where a\n * control's name actually lives: `aria-label`, then a `<label for>` or a wrapping\n * `<label>`, then `placeholder`. `placeholder` is a LABEL, not a value — it is the\n * hint shown when the field is empty (\"Order number or customer\"), so it is safe.\n */\nfunction controlLabel(el: Element): string {\n const aria = el.getAttribute('aria-label');\n if (aria) return aria;\n\n const id = el.id;\n if (id) {\n const forLabel = document.querySelector(`label[for=\"${CSS.escape(id)}\"]`);\n const t = forLabel?.textContent?.trim();\n if (t) return t;\n }\n const wrapping = el.closest('label')?.textContent?.trim();\n if (wrapping) return wrapping;\n\n const placeholder = el.getAttribute('placeholder');\n if (placeholder) return placeholder;\n\n return '';\n}\n\nconst FORM_CONTROLS = new Set(['INPUT', 'SELECT', 'TEXTAREA']);\n\nfunction describe(el: Element): string {\n const role = el.getAttribute('role') || el.tagName.toLowerCase();\n const label =\n el.getAttribute('aria-label') ||\n (FORM_CONTROLS.has(el.tagName)\n ? controlLabel(el)\n : (el as HTMLElement).innerText?.trim().slice(0, 60)) ||\n el.getAttribute('title') ||\n '';\n return label ? `${role} \"${redact(label)}\"` : role;\n}\n\n/**\n * Elements a click is worth recording. Deliberately tight: the point of the activity\n * stream is INTENT (\"the user chose to export\"), and a click on a heading, a label,\n * a card gutter, or blank page is not intent, it is noise. We only log a click that\n * lands on something actionable.\n */\nconst ACTIONABLE =\n 'a[href],button,input,select,textarea,summary,' +\n '[role=\"button\"],[role=\"link\"],[role=\"menuitem\"],[role=\"tab\"],[role=\"option\"],' +\n '[role=\"checkbox\"],[role=\"switch\"],[role=\"radio\"],[onclick],[tabindex]';\n\nfunction onClick(ev: Event) {\n const target = ev.target as Element | null;\n if (!target || !(target instanceof Element)) return;\n\n // Clicking a <label> operates the control it labels — record THAT, not \"clicked\n // label\", so the event reads as the user's actual intent.\n const label = target.closest('label');\n const labelled = label\n ? (label.getAttribute('for') &&\n document.getElementById(label.getAttribute('for')!)) ||\n label.querySelector('input,select,textarea')\n : null;\n\n const actionable = labelled ?? target.closest(ACTIONABLE);\n // No actionable target — a click on text, a gutter, or blank space. That is not an\n // action; dropping it is the whole fix for the click-log noise.\n if (!actionable || isPrivate(actionable)) return;\n\n pushActivity({ type: 'click', summary: `clicked ${describe(actionable)}` });\n}\n\nfunction onSubmit(ev: Event) {\n const el = ev.target as Element | null;\n if (!el || isPrivate(el)) return;\n // The FORM was submitted — never its values.\n pushActivity({ type: 'submit', summary: `submitted ${describe(el)}` });\n}\n\n/**\n * A form field changed.\n *\n * The rule is the same as everywhere else and the temptation here is sharpest:\n * record THAT a field changed and WHICH field (its label), never WHAT it was\n * changed to. `change` fires on exactly the elements whose values are off-limits.\n *\n * One safe exception: a <select>, a checkbox, or a radio chose from a fixed, visible\n * set of options the agent can already see in the snapshot — \"Unpaid\", \"Shipped\".\n * That is a user *choice*, not typed data, so the chosen option's LABEL is fair to\n * include and is the useful part (\"filtered status to Shipped\"). Free-text and\n * numeric inputs get their label only.\n */\nfunction onChange(ev: Event) {\n const el = ev.target as (HTMLElement & { type?: string }) | null;\n if (!el || !(el instanceof Element) || isPrivate(el)) return;\n\n const tag = el.tagName;\n const type = (el as HTMLInputElement).type;\n\n // Never a password/hidden field, and isPrivate already covered data-mf-private.\n if (tag === 'INPUT' && (type === 'password' || type === 'hidden')) return;\n\n let summary = `changed ${describe(el)}`;\n\n if (tag === 'SELECT') {\n const opt = (el as HTMLSelectElement).selectedOptions[0]?.text;\n if (opt) summary = `${describe(el)} → \"${redact(opt)}\"`;\n } else if (type === 'checkbox' || type === 'radio') {\n summary = `${(el as HTMLInputElement).checked ? 'checked' : 'unchecked'} ${describe(el)}`;\n }\n\n pushActivity({ type: 'input', summary });\n}\n\n/**\n * SPA navigation. There is no event for `pushState`, so we wrap it — a 20-line job\n * that no library does better.\n */\nfunction watchNavigation() {\n const fire = () => {\n const url = location.pathname;\n if (url === lastUrl) return;\n lastUrl = url;\n pushActivity({ type: 'nav', summary: `navigated to ${url}` });\n publishContext();\n publishArtifactGrants();\n };\n // Captured so stop() can remove exactly this listener, and so history.pushState/\n // replaceState get restored to what they were before we wrapped them — never\n // re-wrapped on top of an existing wrap (that was the pre-existing bug: a second\n // start() used to wrap the ALREADY-wrapped methods, double-firing every nav).\n navFire = fire;\n\n for (const name of ['pushState', 'replaceState'] as const) {\n const orig = history[name];\n if (name === 'pushState') origPushState = orig as History['pushState'];\n else origReplaceState = orig as History['replaceState'];\n history[name] = function (\n this: History,\n ...args: Parameters<History['pushState']>\n ) {\n const r = orig.apply(this, args);\n fire();\n return r;\n } as History[typeof name];\n }\n window.addEventListener('popstate', fire);\n}\n\n/* ─────────────────────────── focal context ────────────────────────────── */\n\n/**\n * Where the user's attention is, right now.\n *\n * This is the \"knows what you're doing\" layer, and it is deliberately small so it can\n * ride on every turn — where the full snapshot cannot. It is also the most sensitive:\n * `selection` is whatever the user highlighted, which could be their own email, so it\n * is redacted and respects data-mf-private like everything else. Focus and the\n * viewport are labels and refs — never a value.\n *\n * Held so the last-known focus can travel with a turn even between the (throttled)\n * push updates.\n */\nlet lastFocus: FocusContext = {};\n\nasync function readFocus(): Promise<FocusContext> {\n const focus: FocusContext = {};\n\n // Selection — the single strongest \"this is what I'm asking about\" signal.\n const sel = window.getSelection?.();\n if (sel && !sel.isCollapsed) {\n const anchor = sel.anchorNode?.parentElement ?? null;\n // Don't lift a selection out of a private region, and cap it — a user can select\n // the whole page.\n if (!anchor || !anchor.closest('[data-mf-private]')) {\n const text = sel.toString().trim().slice(0, 500);\n if (text) focus.selection = redact(text);\n }\n }\n\n // The control they're working in — its label, never its contents.\n const active = document.activeElement;\n if (\n active &&\n active !== document.body &&\n !isPrivate(active) &&\n !active.closest('[data-mf-private]')\n ) {\n const { snapshot } = await loadSnapshotModule();\n void snapshot; // ensure the chunk that owns refFor is loaded before we describe\n focus.focused = {\n label: redact(describeControl(active)),\n role: active.getAttribute('role') || active.tagName.toLowerCase(),\n };\n }\n\n const doc = document.documentElement;\n const scrollable = doc.scrollHeight - doc.clientHeight;\n focus.scroll =\n scrollable > 0 ? Math.round((doc.scrollTop / scrollable) * 100) / 100 : 0;\n\n return focus;\n}\n\n/** A label for whatever is focused, reusing the same value-blind rules as activity. */\nfunction describeControl(el: Element): string {\n return describe(el);\n}\n\n/** The one place any of the three call sites below reach into the DOM-walk chunk —\n * so `stop()` has a single `snapshotModule` to check without importing anything\n * itself (see the teardown-state block above). */\nasync function loadSnapshotModule() {\n const m = await import('./dom/snapshot');\n snapshotModule = m;\n return m;\n}\n\nlet focusTimer: ReturnType<typeof setTimeout> | null = null;\n\n/** Coalesce a burst of selection/focus/scroll events into one push. */\nfunction scheduleFocus() {\n if (focusTimer) return;\n focusTimer = setTimeout(async () => {\n focusTimer = null;\n lastFocus = await readFocus();\n send?.({ type: 'host.focus', focus: lastFocus });\n }, 250);\n}\n\n/* ───────────────────────────── snapshot ───────────────────────────────── */\n\nlet snapshotSeq = 0;\n\nexport async function sendSnapshot(emit: Send) {\n // pageContext: false ⇒ no snapshot, ever — a `widget.requestSnapshot` must not be\n // able to reintroduce the page observation the host explicitly turned off.\n if (!pageContextOn) return;\n // The a11y walk is itself lazily imported: a host that only ever declares\n // PageContext and never lets the agent look at the page never downloads it.\n const { snapshot } = await loadSnapshotModule();\n const { yaml, truncated, visibleRefs } = snapshot();\n emit({\n type: 'host.snapshot',\n snapshot: { yaml: redact(yaml), seq: ++snapshotSeq, truncated },\n });\n // The viewport slice rides with the focus context so the agent can tell the few\n // things on screen from the whole tree it just received.\n lastFocus = { ...lastFocus, visibleRefs };\n emit({ type: 'host.focus', focus: lastFocus });\n}\n\n/**\n * Zoom in on one ref — the pull half of the model. The agent asks; we resolve the ref\n * to a live element and return just its sub-tree.\n */\nexport async function sendRegion(ref: string, emit: Send) {\n // Mirrors sendSnapshot's guard: a `widget.readRegion` for a ref minted before\n // opt-out must not pull a live DOM subtree just because the ref is still\n // resolvable (see refs.ts's `clearRefs`, which `stop()` also uses as a backstop).\n if (!pageContextOn) return;\n const { snapshotRegion, resolveRef } = await loadSnapshotModule();\n const el = resolveRef(ref);\n if (!el) {\n emit({\n type: 'host.region',\n ref,\n yaml: '(this element is no longer on the page)',\n });\n return;\n }\n const { yaml } = snapshotRegion(el);\n emit({ type: 'host.region', ref, yaml: redact(yaml) });\n}\n\n/* ───────────────────────────── tools ──────────────────────────────────── */\n\n/**\n * v1 IS READ-ONLY.\n *\n * The page's content is untrusted — text on it can try to instruct the agent — and\n * the moment the agent can act, a bad answer becomes a bad ACTION. So no tool here\n * mutates the page yet. The call path exists, and the enforcement point is HERE (in\n * the page, where we control what actually happens) rather than in the widget, which\n * can be lied to.\n *\n * When write tools land: anything not `readOnly` gets a user confirmation, on every\n * call. Not \"unless the host opts out\" — every call, because the trigger may have\n * been written by the page.\n */\nexport async function callTool(call: ToolCall, emit: Send) {\n emit({\n type: 'host.toolResult',\n callId: call.callId,\n ok: false,\n error: 'Host tools are read-only in this version; no action was taken.',\n });\n}\n\n/* ───────────────────────────── auth ───────────────────────────────────── */\n\n/**\n * Hosted login, in a POPUP — and the popup is not a UX preference.\n *\n * Our iframe on acme.com gets a PARTITIONED cookie jar: it cannot see the user's\n * existing matterfact session, no matter that it is served from our own origin.\n * A popup, however, is a TOP-LEVEL window on app.matterfact.com — first-party, real\n * cookies, silent SSO if they are already signed in. It hands the token back by\n * postMessage and we forward it into the iframe.\n */\nexport function beginAuth(\n config: { origin: string; publishableKey: string },\n emit: Send,\n) {\n const w = window.open(\n `${config.origin}/embed/authorize?k=${encodeURIComponent(\n config.publishableKey,\n )}&o=${encodeURIComponent(location.origin)}`,\n 'mf_auth',\n 'width=460,height=640',\n );\n if (!w) return; // popup blocked; the widget shows its own \"sign in\" affordance\n\n // At most one pending popup at a time: a second beginAuth() (a re-click of \"sign\n // in\" before the first popup resolved) would otherwise leave the FIRST listener\n // dangling right alongside this one — tracked at module scope so stop() can also\n // remove it on teardown, same as every other listener this module installs.\n if (pendingAuthListener) window.removeEventListener('message', pendingAuthListener);\n\n const onMsg = (event: MessageEvent) => {\n if (event.origin !== config.origin) return;\n const d = event.data;\n if (d?.type !== 'mf:embed:auth') return;\n window.removeEventListener('message', onMsg);\n pendingAuthListener = null;\n emit({ type: 'host.auth', token: d.token, expiresAt: d.expiresAt });\n };\n pendingAuthListener = onMsg;\n window.addEventListener('message', onMsg);\n}\n\n/* ───────────────────────────── stop / start ───────────────────────────── */\n\n/**\n * The opposite number of `start()` — remove every listener it (or `watchNavigation`,\n * or `beginAuth`) installed, restore `history.pushState`/`replaceState` to what they\n * were before we wrapped them, and forget the module-level `send`/`activity`/focus\n * state. Nothing here is a filter over what gets sent afterward — there is simply\n * nothing left installed to send anything.\n *\n * Why this has to exist at all: everything `start()` installs is MODULE-GLOBAL, and\n * this module outlives any single `EmbedHost`. React remounts `EmbedHost` whenever\n * ANY of its identity-defining props change (react.tsx's effect deps: publishableKey,\n * widgetOrigin, surface, theme, inline, pageContext, dev) — including just a theme\n * swap, not only a deliberate opt-out. Before this fix, a remount's `start()` call\n * only ever ADDED listeners; the previous mount's were still attached and kept firing\n * into the module `send`, which the new `start()` had just repointed at the NEW\n * widget. Net effect: open once with pageContext on, then remount for any reason\n * (including `pageContext: false`) and the new widget silently keeps receiving\n * clicks/nav/focus collected by the old mount's still-live listeners.\n *\n * Called from two places: the top of `start()` (idempotency — a second `start()`\n * never doubles up, which also fixes the pre-existing double history-wrap /\n * double-`fire()`-per-navigation bug), and `EmbedHost.destroy()` in loader.ts (a\n * plain unmount with no remount still has to stop, not just wait for a `start()`\n * that may never come).\n */\nexport function stop(): void {\n document.removeEventListener('click', onClick, { capture: true });\n document.removeEventListener('submit', onSubmit, { capture: true });\n document.removeEventListener('change', onChange, { capture: true });\n document.removeEventListener('selectionchange', scheduleFocus);\n document.removeEventListener('focusin', scheduleFocus, { capture: true });\n window.removeEventListener('scroll', scheduleFocus, { capture: true });\n\n if (navFire) {\n window.removeEventListener('popstate', navFire);\n navFire = null;\n }\n // Restore, don't re-wrap: this is what stops a repeated start() from wrapping an\n // already-wrapped pushState/replaceState (the old double-fire-per-nav bug).\n if (origPushState) {\n history.pushState = origPushState;\n origPushState = null;\n }\n if (origReplaceState) {\n history.replaceState = origReplaceState;\n origReplaceState = null;\n }\n\n if (pendingAuthListener) {\n window.removeEventListener('message', pendingAuthListener);\n pendingAuthListener = null;\n }\n\n if (focusTimer) {\n clearTimeout(focusTimer);\n focusTimer = null;\n }\n\n send = null;\n activity.length = 0;\n lastFocus = {};\n widgetOrigin = '';\n\n // Belt-and-suspenders alongside sendRegion's own pageContextOn check (see above):\n // an old ref minted while observation was on must not stay resolvable afterward.\n // Only touches the DOM-walk chunk if it was ever actually loaded — see\n // loadSnapshotModule's doc comment.\n snapshotModule?.clearRefs();\n}\n\n/**\n * @param pageContext Whether to observe the host page at all. Default `true`. False is\n * the loader's `pageContext: false` opt-out reaching all the way down here: skip every\n * bit of page reading below — no declared/found context, no artifact grants, no nav/\n * click/submit/change/focus observers — so there is nothing to send and nothing that\n * could later be asked for (see `widget.requestSnapshot` in loader.ts). Theme detection\n * is unaffected: it reads an OS media query, never the page, so it isn't page context.\n */\nexport function start(emit: Send, origin?: string, pageContext = true) {\n // Idempotent: undo whatever a PREVIOUS start() installed before this one installs\n // anything. Without this, a remount (see stop()'s doc comment) leaves the old\n // mount's listeners live, writing into the `send` this call is about to reassign.\n stop();\n\n send = emit;\n widgetOrigin = origin || '';\n lastUrl = location.pathname;\n pageContextOn = pageContext;\n\n if (pageContextOn) {\n publishContext();\n publishArtifactGrants();\n watchNavigation();\n\n // Passive + capture: we observe, we never interfere with the host's own handling.\n document.addEventListener('click', onClick, { capture: true, passive: true });\n document.addEventListener('submit', onSubmit, {\n capture: true,\n passive: true,\n });\n // `change` fires on blur/commit for text inputs and immediately for select/\n // checkbox/radio — not on every keystroke, which is what we want: a settled\n // choice, not a stream of partial values.\n document.addEventListener('change', onChange, {\n capture: true,\n passive: true,\n });\n\n // Focal context: what the user is attending to. Coalesced (scheduleFocus), because\n // selectionchange and scroll fire in torrents.\n document.addEventListener('selectionchange', scheduleFocus, {\n passive: true,\n });\n document.addEventListener('focusin', scheduleFocus, {\n capture: true,\n passive: true,\n });\n window.addEventListener('scroll', scheduleFocus, {\n capture: true,\n passive: true,\n });\n }\n\n const theme = matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light';\n emit({ type: 'host.theme', mode: theme });\n}\n"]}
|
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
redact,
|
|
10
10
|
sendRegion,
|
|
11
11
|
sendSnapshot,
|
|
12
|
-
start
|
|
13
|
-
|
|
12
|
+
start,
|
|
13
|
+
stop
|
|
14
|
+
} from "./chunk-SBNMM3ZV.js";
|
|
14
15
|
export {
|
|
15
16
|
artifactIdFromPath,
|
|
16
17
|
beginAuth,
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
redact,
|
|
22
23
|
sendRegion,
|
|
23
24
|
sendSnapshot,
|
|
24
|
-
start
|
|
25
|
+
start,
|
|
26
|
+
stop
|
|
25
27
|
};
|
|
26
|
-
//# sourceMappingURL=context-
|
|
28
|
+
//# sourceMappingURL=context-432WQST4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"context-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"context-KZAUOIR6.js"}
|
package/dist/embed.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s="mf-embed";function d(i,t){return{channel:s,protocol:1,...t?{id:t}:{},payload:i}}function c(i){return typeof i=="object"&&i!==null&&i.channel===s}var b="https://app.matterfact.com";function y(){try{return new URLSearchParams(location.search).get("mfdev")==="1"}catch{return!1}}function p(){let i=document.currentScript??document.querySelector('script[data-key][src*="embed"]'),t=i?.dataset.key;if(!t)return console.error("[matterfact] missing data-key on the embed script tag"),null;let e=i?.dataset.container,n=e?document.querySelector(e):null;e&&!n&&console.error(`[matterfact] data-container="${e}" matched nothing; falling back to the corner`);let o=i?.dataset.pageContext?.toLowerCase();return{publishableKey:t,origin:i?.dataset.origin||b,theme:i?.dataset.theme||"auto",surface:i?.dataset.surface||"",container:n,pageContext:o!=="off"&&o!=="false"&&o!=="0"}}var r="mf.embed.pos",a=class{constructor(t){this.config=t;this.iframe=null;this.shadow=null;this.queue=[];this.ready=!1;this.open=!1;this.expanded=!1;this.pos=null;this.dragBase=null;this.context=null;this.hostEl=null;this.onMessage=t=>{if(t.origin!==this.config.origin||t.source!==this.iframe?.contentWindow||!c(t.data))return;let e=t.data.payload;switch(e.type){case"widget.ready":this.ready=!0,this.send({type:"host.ready",protocol:1,origin:location.origin}),this.flush(),this.inline&&this.loadContext();break;case"widget.setOpen":if(this.inline)break;this.open=e.open,this.iframe?.setAttribute("data-open",String(e.open)),e.open||(this.expanded=!1,this.iframe?.setAttribute("data-expanded","false")),e.open&&this.loadContext();break;case"widget.setExpanded":if(this.inline)break;this.expanded=e.expanded,this.iframe?.setAttribute("data-expanded",String(e.expanded)),this.iframe&&(this.iframe.style.height="");break;case"widget.resize":if(this.inline)break;this.iframe&&this.open&&!this.expanded&&(this.iframe.style.height=`${Math.min(e.height,window.innerHeight-40)}px`);break;case"widget.requestSnapshot":this.loadContext().then(n=>n.sendSnapshot(this.send));break;case"widget.readRegion":this.loadContext().then(n=>n.sendRegion(e.ref,this.send));break;case"widget.callTool":this.loadContext().then(n=>n.callTool(e.call,this.send));break;case"widget.dragStart":if(this.inline)break;this.dragBase=this.cornerOffset();break;case"widget.dragMove":if(this.inline)break;this.dragTo(e.dx,e.dy);break;case"widget.dragEnd":if(this.inline)break;this.dragBase=null,this.writePos(this.pos);break;case"widget.setMenu":if(this.inline)break;this.iframe&&!this.open&&(this.iframe.style.height=e.open?`${64+e.height}px`:"");break;case"widget.resetPos":if(this.inline)break;this.resetPos();break;case"widget.hide":if(this.inline)break;this.hostEl&&(this.hostEl.style.display="none");break;case"widget.needsAuth":this.provideAuth();break}};this.send=t=>{if(!this.ready){this.queue.push(t);return}this.iframe?.contentWindow?.postMessage(d(t),this.config.origin)};this.inline=!!t.container}mount(){let t=document.createElement("div");this.hostEl=t,t.id="matterfact-embed",this.inline?(t.style.cssText=["all: initial","position: relative","display: block","width: 100%","height: 100%","contain: layout style"].join(";"),this.config.container.appendChild(t)):(this.pos=this.readPos(),t.style.cssText=["all: initial","position: fixed",`right: ${this.pos?this.pos.right:20}px`,`bottom: ${this.pos?this.pos.bottom:20}px`,"z-index: 2147483000","contain: layout style"].join(";"),document.body.appendChild(t)),this.shadow=t.attachShadow({mode:"closed"});let e=document.createElement("style");e.textContent=":host{all:initial}iframe{border:0;display:block;color-scheme:light dark;}"+(this.inline?"iframe{width:100%;height:100%}":'iframe{border-radius:12px;box-shadow:0 0 0 1px #00000014,0 8px 40px #00000029;width:400px;height:64px;transition:height .18s ease,width .18s ease}iframe[data-open="true"]{width:420px;height:640px}iframe[data-open="true"][data-expanded="true"]{width:min(600px,calc(100vw - 40px));height:calc(100vh - 40px)}'),this.shadow.appendChild(e);let n=document.createElement("iframe");n.title="matterfact assistant",n.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"),n.setAttribute("allow","microphone"),n.src=`${this.config.origin}/embed/chat?k=${encodeURIComponent(this.config.publishableKey)}&o=${encodeURIComponent(location.origin)}`+(this.config.surface?`&s=${encodeURIComponent(this.config.surface)}`:"")+(y()||this.config.dev?"&dev=1":"")+(this.inline?"&inline=1":""),this.iframe=n,this.shadow.appendChild(n),window.addEventListener("message",this.onMessage)}cornerOffset(){let t=this.hostEl.getBoundingClientRect();return{right:window.innerWidth-t.right,bottom:window.innerHeight-t.bottom}}dragTo(t,e){if(!this.dragBase||!this.hostEl)return;let n=this.hostEl.getBoundingClientRect(),o=Math.max(0,window.innerWidth-n.width),m=Math.max(0,window.innerHeight-n.height),l=Math.min(Math.max(0,this.dragBase.right-t),o),h=Math.min(Math.max(0,this.dragBase.bottom-e),m);this.pos={right:l,bottom:h},this.hostEl.style.right=`${l}px`,this.hostEl.style.bottom=`${h}px`}resetPos(){this.pos=null,this.writePos(null),this.hostEl&&(this.hostEl.style.right="20px",this.hostEl.style.bottom="20px")}readPos(){try{let t=localStorage.getItem(r);if(!t)return null;let e=JSON.parse(t);return typeof e?.right=="number"&&typeof e?.bottom=="number"?{right:e.right,bottom:e.bottom}:null}catch{return null}}writePos(t){try{t?localStorage.setItem(r,JSON.stringify(t)):localStorage.removeItem(r)}catch{}}async provideAuth(){let t=this.config.authTokenProvider??globalThis.matterfact?.getEmbedAuthToken;if(t)try{let e=await t();if(e){this.send({type:"host.auth",token:e,expiresAt:0});return}}catch{}this.loadContext().then(e=>e.beginAuth(this.config,this.send))}loadContext(){return this.context??(this.context=import("./chunk-URIBHOOQ.js").then(t=>(t.start(this.send,this.config.origin,this.config.pageContext),this.config.theme!=="auto"&&this.send({type:"host.theme",mode:this.config.theme}),t))),this.context}flush(){let t=this.queue;this.queue=[];for(let e of t)this.send(e)}destroy(){window.removeEventListener("message",this.onMessage),this.hostEl?.remove(),this.hostEl=null,this.iframe=null,this.shadow=null,this.ready=!1,this.context?.then(t=>t.stop())}};function g(i){let t=new a(i);return t.mount(),t}var u=p();if(u){let i=()=>g(u);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i,{once:!0}):i()}
|
|
2
2
|
//# sourceMappingURL=embed.js.map
|
package/dist/embed.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/protocol.ts", "../src/loader.ts", "../src/embed.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * The matterfact embed bridge protocol.\n *\n * This is the contract between the HOST PAGE (a customer's site, running our\n * loader) and the WIDGET (our chat, running in a cross-origin iframe on\n * app.matterfact.com).\n *\n * Two things to understand before changing anything here:\n *\n * 1. THE IFRAME CANNOT SEE THE PAGE. It is cross-origin \u2014 that is the entire\n * point of it. So every fact about the host page (its URL, its DOM, what the\n * user just did) reaches the agent only because the LOADER, which runs as\n * ordinary page JS and *can* see it, chose to send it. The loader is the eye;\n * the widget is the mouth.\n *\n * 2. THIS CONTRACT OUTLIVES THE IFRAME. The next tier is an in-page React SDK\n * with no iframe at all \u2014 and it will speak exactly this. If the message\n * shapes are right, \"deeper integration\" is a transport swap (postMessage ->\n * direct call), not a rewrite. So model the DOMAIN here, not the plumbing.\n */\n\nexport const PROTOCOL_VERSION = 1;\n\n/** Every message is namespaced so we never collide with the host page's own postMessage traffic. */\nexport const CHANNEL = 'mf-embed';\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * A handle on a real element in the host page.\n *\n * Format and semantics are lifted from Playwright's ARIA snapshot (`ref=e12`),\n * for a specific reason: it is the element-handle syntax the frontier models have\n * seen most, via playwright-mcp. We are not being original here on purpose.\n *\n * The ref is an in-page expando plus a snapshot-scoped Map \u2014 never an attribute,\n * so it is invisible to the host page's CSS, its serialization, and its own\n * mutation observers. It is resolved back to an element by the LOADER; the agent\n * never touches the DOM, and never learns a selector.\n */\nexport type ElementRef = string; // 'e12'\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 host \u2192 widget \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** Ambient facts about the page. Cheap, sent on every navigation. */\nexport interface PageContext {\n url?: string;\n /** A route PATTERN ('/orders/:id') beats a raw path \u2014 it tells the agent what KIND of page this is. */\n route?: string;\n path?: string;\n title?: string;\n locale?: string;\n /** 1\u20132 sentences, written the way you'd brief a colleague. The highest-value field by far. */\n description?: string;\n /** Things the page is about. These also become @-mentionable in the composer, for free. */\n entities?: PageEntity[];\n /** Allowlisted only. Never a dump of app state. */\n data?: Record<string, unknown>;\n}\n\nexport interface PageEntity {\n /** Host kinds are namespaced (`x:ticker`) so they can never collide with matterfact's own. */\n kind: string;\n id: string;\n label: string;\n /** Pre-rendered, agent-readable. Keep it short. */\n text?: string;\n data?: Record<string, unknown>;\n}\n\n/** A co-embedded artifact's read-only capability, for the backend to materialize its\n * data. Backend-only \u2014 never rendered. `token` is the artifact's own embed token. */\nexport interface ArtifactGrant {\n id: string;\n owner: string;\n token: string;\n}\n\n/**\n * A snapshot of the page as the agent sees it.\n *\n * `yaml` is Playwright's ARIA-snapshot rendering \u2014 role, accessible name, state,\n * and a ref on anything interactable:\n *\n * - heading \"Orders\" [level=1]\n * - textbox \"Search orders\" [ref=e5]\n * - button \"Export CSV\" [ref=e9]\n *\n * NOT raw HTML. A real page is tens of thousands of tokens of div soup, it gives\n * the model no handle to act with, and it is a prompt-injection firehose. The\n * a11y tree is a tenth the size and is the only signal that survives in-page \u2014\n * `getEventListeners()` is DevTools-only, so listener-sniffing (the browser-use\n * approach) cannot see a single React handler on a real customer's app.\n */\nexport interface DomSnapshot {\n yaml: string;\n /** Monotonic. A ref is only valid within the snapshot that minted it. */\n seq: number;\n /** True when the walk hit its node budget and stopped. The agent must be told it is not seeing everything. */\n truncated: boolean;\n}\n\n/**\n * Where the user's attention is RIGHT NOW.\n *\n * This is the difference between an assistant that can read your page and one that\n * knows what you're doing. A full DOM snapshot answers \"what is on this screen\"; this\n * answers \"what are you looking at and working in\" \u2014 which is what a colleague\n * leaning over reads first. It is small, so it rides on every turn, where the full\n * snapshot does not.\n *\n * Every field here is a LABEL or a REF, never a value. `selection` is the sharpest\n * intent signal there is (\"this is the thing I'm asking about\"), and for exactly that\n * reason it is also where a user might have highlighted their own email \u2014 so it is\n * redacted and honours data-mf-private like everything else.\n */\nexport interface FocusContext {\n /** Text the user has selected. The single strongest \"I'm asking about this\" signal. Redacted. */\n selection?: string;\n /** The control the user is working IN \u2014 by label and ref, never its contents. */\n focused?: { ref?: ElementRef; label: string; role: string };\n /** The refs currently in the viewport: the handful of things actually on screen, out of the whole tree. */\n visibleRefs?: ElementRef[];\n /** How far down the page they are, 0\u20131. A cheap proxy for \"which part am I reading\". */\n scroll?: number;\n}\n\n/** Something the user did. Shaped after PostHog's autocapture \u2014 one readable line, not a replay frame. */\nexport interface ActivityEvent {\n seq: number;\n ts: number;\n type: 'nav' | 'click' | 'input' | 'submit' | 'selection' | 'custom';\n /** Human-readable: 'clicked button \"Export CSV\"'. Semantic, not coordinates. */\n summary: string;\n ref?: ElementRef;\n data?: Record<string, unknown>;\n}\n\n/**\n * A tool the HOST page exposes to the agent.\n *\n * Deliberately shaped as a superset of WebMCP (`navigator.modelContext`, W3C\n * WebML CG draft / Chrome origin trial). A customer who adopts WebMCP should be\n * able to hand us their existing tool declarations unchanged.\n */\nexport interface HostTool {\n name: string;\n description: string;\n /** JSON Schema. */\n inputSchema: Record<string, unknown>;\n /**\n * A read-only tool may run without asking. Anything that MUTATES the page\n * requires the user to confirm, every time \u2014 see the note on ToolCall.\n */\n readOnly?: boolean;\n}\n\nexport type HostToWidget =\n | { type: 'host.ready'; protocol: number; origin: string }\n | { type: 'host.context'; context: PageContext }\n | { type: 'host.focus'; focus: FocusContext }\n | { type: 'host.snapshot'; snapshot: DomSnapshot }\n | { type: 'host.region'; ref: ElementRef; yaml: string }\n | { type: 'host.activity'; events: ActivityEvent[] }\n | { type: 'host.artifactGrants'; grants: ArtifactGrant[] }\n | { type: 'host.tools'; tools: HostTool[] }\n | {\n type: 'host.toolResult';\n callId: string;\n ok: boolean;\n result?: unknown;\n error?: string;\n }\n | { type: 'host.auth'; token: string; expiresAt: number }\n | { type: 'host.theme'; mode: 'light' | 'dark' };\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 widget \u2192 host \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * The agent asking the host to do something.\n *\n * THE SECURITY MODEL, stated once: the page's content is UNTRUSTED. Text on the\n * page can try to instruct the agent, and the moment the agent can act, that stops\n * being a bad answer and becomes a bad ACTION. So:\n *\n * - v1 is READ-ONLY. `snapshot` and `activity` flow; no tool mutates the page.\n * - A tool that is not `readOnly` must be confirmed by the USER, every call. Not\n * \"unless the host opts out\" \u2014 every call. The trigger may have been written by\n * the page.\n * - The host is the enforcement point, not the widget. The widget can be lied to;\n * the loader runs in the page and decides what actually happens.\n */\nexport interface ToolCall {\n callId: string;\n name: string;\n args: Record<string, unknown>;\n}\n\nexport type WidgetToHost =\n | { type: 'widget.ready'; protocol: number }\n /**\n * Ask for the FULL page snapshot. This is the agent PULLING detail, not us pushing\n * it: the focus context rides on every turn, but the whole tree is fetched only\n * when the agent decides it needs to look \u2014 cheaper, and it reads what's relevant\n * to the question instead of drowning in the footer nav every turn.\n */\n | { type: 'widget.requestSnapshot' }\n /** Zoom in: the a11y sub-tree under one ref (a table, a form, a card the agent cares about). */\n | { type: 'widget.readRegion'; ref: ElementRef }\n | { type: 'widget.callTool'; call: ToolCall }\n /** Chat opened/closed \u2014 the loader resizes the iframe and starts/stops observing. */\n | { type: 'widget.setOpen'; open: boolean }\n | { type: 'widget.resize'; height: number }\n /**\n * Maximize / restore. Expanded makes the iframe fill the viewport (with a small\n * margin) so the composer's `/` picker, mention previews, and the transcript have\n * room the corner popup can't give them. The loader owns the iframe size, so only\n * it can do this \u2014 `widget.resize` (height-only) can't widen the popup.\n */\n | { type: 'widget.setExpanded'; expanded: boolean }\n /**\n * Launcher drag. The widget tracks the gesture; the host only moves the element.\n *\n * It has to be this way round, and the reason is easy to get wrong: a press that starts\n * inside an iframe is implicitly captured by that iframe, so every pointermove and the\n * pointerup belong to the widget's document until the button comes up. The host cannot\n * see them at all \u2014 not even through an overlay of its own, because capture beats hit\n * testing. So the host cannot take over a drag mid-gesture; it can only be told.\n *\n * `dx`/`dy` are deltas in SCREEN coordinates, which is the other half of the trick:\n * client coordinates are measured against the iframe's own viewport, and the iframe is\n * being moved under the cursor as the drag proceeds \u2014 so the pointer would appear to\n * stop moving and the launcher would stall after one step. Screen coordinates are\n * absolute and immune to that feedback loop.\n */\n | { type: 'widget.dragStart' }\n | { type: 'widget.dragMove'; dx: number; dy: number }\n | { type: 'widget.dragEnd' }\n /**\n * Grow/shrink the iframe to fit the launcher's context menu. The collapsed launcher is\n * only ~64px tall, so a menu rendered inside it would be clipped by the iframe's own\n * bounds \u2014 the host has to make room before it can be seen. `widget.resize` can't do\n * this: it's height-only AND ignored while closed.\n */\n | { type: 'widget.setMenu'; open: boolean; height: number }\n /** Put the launcher back in the default corner and forget the dragged position. */\n | { type: 'widget.resetPos' }\n /** Get out of the way until the page reloads (a menu action, not a setting). */\n | { type: 'widget.hide' }\n /** The widget has no session; the host must run the hosted-login popup. */\n | { type: 'widget.needsAuth' };\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 envelope \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Everything on the wire is wrapped.\n *\n * `channel` keeps us out of the host page's own postMessage traffic (and out of\n * every other widget's). The receiver ALSO checks `event.origin` against an\n * allowlist and `event.source` against the expected window, on every single\n * message \u2014 a namespace is not a security boundary, it is a politeness.\n */\nexport interface Envelope<T> {\n channel: typeof CHANNEL;\n protocol: number;\n /** Correlates a response to its request; absent for notifications. */\n id?: string;\n payload: T;\n}\n\nexport function envelope<T>(payload: T, id?: string): Envelope<T> {\n return {\n channel: CHANNEL,\n protocol: PROTOCOL_VERSION,\n ...(id ? { id } : {}),\n payload,\n };\n}\n\nexport function isEnvelope(data: unknown): data is Envelope<unknown> {\n return (\n typeof data === 'object' &&\n data !== null &&\n (data as { channel?: unknown }).channel === CHANNEL\n );\n}\n", "import {\n CHANNEL,\n PROTOCOL_VERSION,\n envelope,\n isEnvelope,\n type HostToWidget,\n type WidgetToHost,\n} from './protocol';\n\n/**\n * The matterfact embed loader.\n *\n * <script src=\"https://cdn.matterfact.com/embed.js\"\n * data-key=\"pk_live_acme_...\"\n * defer></script>\n *\n * This file runs on EVERY page load of a customer's site, so it is deliberately\n * tiny and deliberately dumb:\n *\n * - zero dependencies\n * - it does NOT read the DOM. The snapshot/activity code is a separate chunk,\n * fetched only when the user actually opens the chat. A customer should pay\n * nothing for a widget nobody clicked.\n * - it does NOT bundle React, or a CSS framework, or an RPC library.\n *\n * `iframe-resizer` is the thing you will be tempted to reach for here. It is\n * GPL-3.0 and cannot ship in this file. The ResizeObserver bridge below is the\n * fifteen lines it would have cost you anyway.\n */\n\n/** Returns a token this matterfact deployment's auth provider trusts (Firebase idToken,\n * Entra token, \u2026). May be async; return null when there's no signed-in user. */\nexport type AuthTokenProvider = () => string | null | Promise<string | null>;\n\nexport interface LoaderConfig {\n publishableKey: string;\n /** Origin of the widget. Overridable for dev/self-hosted; defaults to production. */\n origin: string;\n theme: 'light' | 'dark' | 'auto';\n /** Optional label identifying THIS embedding, when one app embeds the agent in more\n * than one place (e.g. \"orders\" vs \"support\"). Stamped on runs/threads so usage and\n * history can be told apart per surface. Free-form; the app_id (from the session)\n * is the trusted half. */\n surface: string;\n /**\n * OPTIONAL host-auth passthrough, for TRUSTED first-party embeds (the admin portal,\n * EMC). When set, the host page already holds a token this deployment's auth provider\n * trusts (its Firebase idToken, an Entra token, \u2026); the loader hands it to the widget\n * on `widget.needsAuth` instead of opening a sign-in popup. The backend still verifies\n * the token, so identity can't be forged \u2014 this only skips a redundant second sign-in.\n * Called on demand (so tokens can refresh). Absent \u21D2 the popup/inline sign-in flow.\n * The `<script>` loader has no config here; it reads window.matterfact.getEmbedAuthToken\n * instead (see provideAuth).\n */\n authTokenProvider?: AuthTokenProvider;\n /**\n * Render INTO this element instead of floating in the corner \u2014 for a host that has its\n * own side panel, tool drawer or tab and wants the agent to live there.\n *\n * This inverts who owns the chrome. In corner mode the widget owns everything: it draws\n * its own launcher and it tells us how big to be (setOpen/setExpanded/resize). Inside\n * someone else's panel, both are theirs \u2014 a widget that resized its host's drawer, or\n * drew a second floating bubble inside it, is just broken. So here we fill the\n * container, ignore the size messages, and the widget skips the launcher and renders\n * the chat directly.\n *\n * The host also owns visibility: showing and hiding their own panel IS the open/close\n * control, so there is nothing for us to add.\n */\n container?: HTMLElement | null;\n}\n\nconst DEFAULT_ORIGIN = 'https://app.matterfact.com';\n\n/**\n * Has someone asked to see what the widget is doing? `?mfdev=1` on the HOST page.\n *\n * Driven by the host's own URL rather than a `data-` attribute on purpose: an engineer\n * debugging a page they didn't write can add a query param, but they cannot redeploy the\n * customer's site to change a script tag. It's also ephemeral \u2014 it lasts exactly as long\n * as that URL, so nobody can leave it on by accident.\n *\n * This only surfaces what the widget already collects FROM THE PAGE IT'S ON, to the\n * person whose page it is. It grants no access: the session, the origin allowlist and\n * the route scope are all enforced server-side and none of them consult this.\n */\nfunction devRequested(): boolean {\n try {\n return new URLSearchParams(location.search).get('mfdev') === '1';\n } catch {\n return false;\n }\n}\n\nfunction readConfig(): LoaderConfig | null {\n // `document.currentScript` is null inside a module or after async execution, so\n // fall back to finding our own tag by src.\n const el =\n (document.currentScript as HTMLScriptElement | null) ??\n document.querySelector<HTMLScriptElement>('script[data-key][src*=\"embed\"]');\n\n const publishableKey = el?.dataset.key;\n if (!publishableKey) {\n console.error('[matterfact] missing data-key on the embed script tag');\n return null;\n }\n // `data-container=\"#panel\"` renders into the host's own element instead of the\n // corner. A selector rather than an element, because a script tag can't hand us a\n // reference \u2014 and if it doesn't resolve we fall back to the corner rather than\n // vanish: a widget nobody can find looks identical to a broken install.\n const sel = el?.dataset.container;\n const container = sel ? document.querySelector<HTMLElement>(sel) : null;\n if (sel && !container) {\n console.error(\n `[matterfact] data-container=\"${sel}\" matched nothing; falling back to the corner`,\n );\n }\n\n return {\n publishableKey,\n origin: el?.dataset.origin || DEFAULT_ORIGIN,\n theme: (el?.dataset.theme as LoaderConfig['theme']) || 'auto',\n surface: el?.dataset.surface || '',\n container,\n };\n}\n\n/** Where the user dragged the launcher, in px from the viewport's bottom-right. */\ninterface DragPos {\n right: number;\n bottom: number;\n}\n\nconst POS_KEY = 'mf.embed.pos';\n\nclass EmbedHost {\n private iframe: HTMLIFrameElement | null = null;\n private shadow: ShadowRoot | null = null;\n /** Buffered until the widget says it's listening \u2014 postMessage before load is dropped silently. */\n private queue: HostToWidget[] = [];\n private ready = false;\n private open = false;\n private expanded = false;\n /** Null until the user drags; then it pins the corner offset and survives reloads. */\n private pos: DragPos | null = null;\n /** Where the launcher sat when the current drag began; deltas are applied to this. */\n private dragBase: DragPos | null = null;\n /** Loaded on first open. Holds everything that touches the customer's DOM. */\n private context: Promise<typeof import('./context')> | null = null;\n /** The host element; kept so `destroy()` can remove it (React lifecycle). */\n private hostEl: HTMLDivElement | null = null;\n /** Rendering into the host's own element: they own the box, the chrome and visibility. */\n private readonly inline: boolean;\n\n constructor(private config: LoaderConfig) {\n this.inline = !!config.container;\n }\n\n mount() {\n // A CLOSED shadow root, on a container that resets every inherited property.\n //\n // We are a guest on someone else's page. Their CSS must not reach into us, our\n // CSS must not leak out, and their JS should not be able to walk into our tree\n // by accident (closed mode: `host.shadowRoot` is null). `contain` stops our\n // layout/paint from invalidating theirs.\n const host = document.createElement('div');\n this.hostEl = host;\n host.id = 'matterfact-embed';\n\n if (this.inline) {\n // The container's box IS the widget's box. No fixed positioning, no z-index\n // scramble, no drag: where this sits is the host's layout problem, which is the\n // entire point of asking for it.\n host.style.cssText = [\n 'all: initial',\n 'position: relative',\n 'display: block',\n 'width: 100%',\n 'height: 100%',\n 'contain: layout style',\n ].join(';');\n this.config.container!.appendChild(host);\n } else {\n this.pos = this.readPos();\n host.style.cssText = [\n 'all: initial',\n 'position: fixed',\n `right: ${this.pos ? this.pos.right : 20}px`,\n `bottom: ${this.pos ? this.pos.bottom : 20}px`,\n // Below the max so a host that genuinely needs to cover us (a modal, a cookie\n // banner they are legally obliged to show) still can.\n 'z-index: 2147483000',\n 'contain: layout style',\n ].join(';');\n document.body.appendChild(host);\n }\n\n this.shadow = host.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n // Shared prefix, then only what differs. This ships on every page load and the stub\n // has ~no headroom, so the two modes must not each carry a whole stylesheet.\n //\n // Inline fills the host's box and adds nothing: no radius, no shadow. Their panel\n // already has whatever chrome they chose; ours would sit inside it looking like a\n // mistake.\n style.textContent =\n ':host{all:initial}iframe{border:0;display:block;color-scheme:light dark;}' +\n (this.inline\n ? 'iframe{width:100%;height:100%}'\n : // Hairline ring + soft ambient: the widget must read as a crisp card on\n // ANY host background, including pure white where a shadow alone bleeds.\n 'iframe{border-radius:12px;box-shadow:0 0 0 1px #00000014,0 8px 40px #00000029;width:400px;' +\n 'height:64px;transition:height .18s ease,width .18s ease}' +\n 'iframe[data-open=\"true\"]{width:420px;height:640px}' +\n // Expanded: a full-height SIDE PANEL docked to the host's right edge, not a\n // viewport-covering overlay \u2014 room for the composer's slash-picker and mention\n // previews, capped to the viewport on narrow screens.\n 'iframe[data-open=\"true\"][data-expanded=\"true\"]{width:min(600px,calc(100vw - 40px));' +\n 'height:calc(100vh - 40px)}');\n this.shadow.appendChild(style);\n\n const iframe = document.createElement('iframe');\n iframe.title = 'matterfact assistant';\n //\n // `allow-same-origin` is REQUIRED, and leaving it out is the trap.\n //\n // Without it the framed document gets an OPAQUE origin: its postMessage arrives\n // as `event.origin === \"null\"`, so our own origin check rejects the handshake and\n // the bridge silently never connects. It also denies the widget any storage at\n // all \u2014 no session, no auth, ever.\n //\n // The familiar warning \u2014 \"allow-scripts + allow-same-origin lets the frame escape\n // its sandbox\" \u2014 is about a frame that is SAME-ORIGIN WITH THE FRAMER, which can\n // then reach up and delete its own sandbox attribute. Ours is cross-origin to the\n // host by construction (that is the entire security model), so it cannot touch\n // this element. What the sandbox still buys us is real: no top-level navigation,\n // no downloads, no pointer lock.\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox',\n );\n // Dictation needs an explicit permissions-policy grant: without `allow`,\n // getUserMedia inside the frame is hard-blocked no matter what the user\n // approves. The bare token scopes the grant to the iframe's own origin\n // (the app), not the host page. A host page can still deny the feature\n // via its own Permissions-Policy response header \u2014 outside our control.\n iframe.setAttribute('allow', 'microphone');\n iframe.src =\n `${this.config.origin}/embed/chat?k=${encodeURIComponent(\n this.config.publishableKey,\n )}&o=${encodeURIComponent(location.origin)}` +\n (this.config.surface\n ? `&s=${encodeURIComponent(this.config.surface)}`\n : '') +\n (devRequested() ? '&dev=1' : '') +\n (this.inline ? '&inline=1' : '');\n this.iframe = iframe;\n this.shadow.appendChild(iframe);\n\n window.addEventListener('message', this.onMessage);\n }\n\n /**\n * Every message is checked twice, on every single message \u2014 not once at setup.\n *\n * `channel` is a namespace, not a boundary. The origin and source checks are the\n * boundary: any frame on the page can postMessage us, and a page with an ad iframe\n * on it has plenty of frames.\n */\n private onMessage = (event: MessageEvent) => {\n if (event.origin !== this.config.origin) return;\n if (event.source !== this.iframe?.contentWindow) return;\n if (!isEnvelope(event.data)) return;\n\n const msg = event.data.payload as WidgetToHost;\n\n switch (msg.type) {\n case 'widget.ready':\n this.ready = true;\n this.send({\n type: 'host.ready',\n protocol: PROTOCOL_VERSION,\n origin: location.origin,\n });\n this.flush();\n // Inline has no \"open\" event to hang this off \u2014 the chat is visible the moment\n // the host renders their panel, so the eye has to load now or the agent is\n // blind to the page for the whole session. The corner keeps its lazy load: a\n // page whose visitors never click still pays nothing.\n if (this.inline) void this.loadContext();\n break;\n\n case 'widget.setOpen':\n // Inline: the host's panel IS the open/close control. There's no popup to size.\n if (this.inline) break;\n this.open = msg.open;\n this.iframe?.setAttribute('data-open', String(msg.open));\n // Closing the popup always restores it \u2014 a widget that reopens should start\n // at the corner size, not wherever it was maximized to last time.\n if (!msg.open) {\n this.expanded = false;\n this.iframe?.setAttribute('data-expanded', 'false');\n }\n // The DOM code is fetched HERE \u2014 the first time someone actually opens the\n // chat \u2014 and never on a page where they don't.\n if (msg.open) void this.loadContext();\n break;\n\n case 'widget.setExpanded':\n // Inline: \"maximize\" would mean resizing someone else's panel from inside it.\n if (this.inline) break;\n this.expanded = msg.expanded;\n this.iframe?.setAttribute('data-expanded', String(msg.expanded));\n // A prior widget.resize set an inline height; clear it so the maximized CSS\n // (and, on restore, the popup CSS) wins.\n if (this.iframe) this.iframe.style.height = '';\n break;\n\n case 'widget.resize':\n // Inline: the container's height is the host's business, and an auto-grow here\n // would fight their layout every time the transcript got longer.\n if (this.inline) break;\n // Height auto-grow is for the corner popup only; when maximized the CSS owns\n // the size, so don't let a resize shrink it back.\n if (this.iframe && this.open && !this.expanded) {\n this.iframe.style.height = `${Math.min(msg.height, window.innerHeight - 40)}px`;\n }\n break;\n\n case 'widget.requestSnapshot':\n void this.loadContext().then((m) => m.sendSnapshot(this.send));\n break;\n\n case 'widget.readRegion':\n void this.loadContext().then((m) => m.sendRegion(msg.ref, this.send));\n break;\n\n case 'widget.callTool':\n void this.loadContext().then((m) => m.callTool(msg.call, this.send));\n break;\n\n // Everything below is LAUNCHER chrome: there is no launcher inline (the widget\n // doesn't draw one), and moving or hiding the host's own panel from inside it\n // would be us redecorating their app. An older cached loader could still be told\n // any of these by a newer widget, so they're guarded rather than assumed absent.\n case 'widget.dragStart':\n if (this.inline) break;\n this.dragBase = this.cornerOffset();\n break;\n\n case 'widget.dragMove':\n if (this.inline) break;\n this.dragTo(msg.dx, msg.dy);\n break;\n\n case 'widget.dragEnd':\n if (this.inline) break;\n this.dragBase = null;\n this.writePos(this.pos);\n break;\n\n case 'widget.setMenu':\n if (this.inline) break;\n // Make room for the launcher's menu. Only meaningful while collapsed \u2014 open,\n // the popup is already taller than any menu.\n if (this.iframe && !this.open) {\n this.iframe.style.height = msg.open ? `${64 + msg.height}px` : '';\n }\n break;\n\n case 'widget.resetPos':\n if (this.inline) break;\n this.resetPos();\n break;\n\n case 'widget.hide':\n // Inline: hiding is the host's panel to hide. Blanking their drawer from in\n // here would leave them with an empty box and no way to get it back.\n if (this.inline) break;\n if (this.hostEl) this.hostEl.style.display = 'none';\n break;\n\n case 'widget.needsAuth':\n void this.provideAuth();\n break;\n }\n };\n\n /**\n * Own a drag for its lifetime.\n *\n * The widget reports the press and then goes quiet: a cross-origin iframe only gets\n * pointer events while the pointer is over it, and a drag leaves that box immediately.\n * So we lay a transparent layer over the whole viewport and track the gesture in the\n * host document, where it can't be lost. The layer also stops the pointer landing on\n * the customer's own UI mid-drag (text selection, hover states, stray clicks).\n *\n * We are the dumb half on purpose \u2014 see `widget.dragMove` in the protocol for why the\n * widget has to own the gesture. All we do is take a delta and place the element.\n */\n private cornerOffset(): DragPos {\n const rect = this.hostEl!.getBoundingClientRect();\n return {\n right: window.innerWidth - rect.right,\n bottom: window.innerHeight - rect.bottom,\n };\n }\n\n private dragTo(dx: number, dy: number) {\n if (!this.dragBase || !this.hostEl) return;\n const rect = this.hostEl.getBoundingClientRect();\n // Clamp to the viewport: the position persists, so letting someone drop the launcher\n // off-screen would strand it there across reloads with no way back to it.\n const maxRight = Math.max(0, window.innerWidth - rect.width);\n const maxBottom = Math.max(0, window.innerHeight - rect.height);\n const right = Math.min(Math.max(0, this.dragBase.right - dx), maxRight);\n const bottom = Math.min(Math.max(0, this.dragBase.bottom - dy), maxBottom);\n this.pos = { right, bottom };\n this.hostEl.style.right = `${right}px`;\n this.hostEl.style.bottom = `${bottom}px`;\n }\n\n /** Reset to the default corner (a menu action \u2014 the drag is otherwise sticky). */\n private resetPos() {\n this.pos = null;\n this.writePos(null);\n if (this.hostEl) {\n this.hostEl.style.right = '20px';\n this.hostEl.style.bottom = '20px';\n }\n }\n\n private readPos(): DragPos | null {\n // First-party storage on the CUSTOMER's origin, so each site remembers its own spot.\n // Never throws: storage is unavailable in some embedding contexts, and a widget that\n // can't remember where it was put is fine \u2014 one that fails to mount is not.\n try {\n const raw = localStorage.getItem(POS_KEY);\n if (!raw) return null;\n const p = JSON.parse(raw) as Partial<DragPos>;\n return typeof p?.right === 'number' && typeof p?.bottom === 'number'\n ? { right: p.right, bottom: p.bottom }\n : null;\n } catch {\n return null;\n }\n }\n\n private writePos(pos: DragPos | null) {\n try {\n if (pos) localStorage.setItem(POS_KEY, JSON.stringify(pos));\n else localStorage.removeItem(POS_KEY);\n } catch {\n /* storage denied \u2014 the position just won't survive the reload */\n }\n }\n\n /**\n * Answer `widget.needsAuth`. If a trusted first-party host has an auth-token provider,\n * call it and hand the token straight to the widget via `host.auth` \u2014 no popup. The\n * provider comes from EITHER the programmatic config (the React `<MatterfactAgent\n * getAuthToken>` prop) OR a global the host page sets for the `<script>` loader:\n *\n * window.matterfact = { getEmbedAuthToken: () => getIdToken(user) };\n *\n * Read fresh at call time (not at readConfig), so a global set after the loader booted\n * \u2014 e.g. once the host's auth is ready \u2014 is still picked up. Otherwise fall back to the\n * hosted-login popup. `expiresAt: 0`: the widget doesn't cache it, it exchanges the\n * token for a rotating embed session anyway.\n */\n private async provideAuth() {\n const provider =\n this.config.authTokenProvider ??\n (globalThis as { matterfact?: { getEmbedAuthToken?: AuthTokenProvider } })\n .matterfact?.getEmbedAuthToken;\n if (provider) {\n try {\n const token = await provider();\n if (token) {\n this.send({ type: 'host.auth', token, expiresAt: 0 });\n return;\n }\n } catch {\n /* fall through to the popup */\n }\n }\n void this.loadContext().then((m) => m.beginAuth(this.config, this.send));\n }\n\n private loadContext() {\n // One chunk, one fetch, cached. Everything that can see the customer's page\n // lives behind this boundary.\n this.context ??= import('./context').then((m) => {\n m.start(this.send, this.config.origin);\n // start() emits the OS-preference theme. An explicit data-theme on the\n // script tag is the host's choice \u2014 resend it so it wins over auto-detect\n // (a light-branded site must be able to force a light widget on a dark-OS\n // visitor, and vice versa).\n if (this.config.theme !== 'auto') {\n this.send({ type: 'host.theme', mode: this.config.theme });\n }\n return m;\n });\n return this.context;\n }\n\n private send = (msg: HostToWidget) => {\n if (!this.ready) {\n this.queue.push(msg);\n return;\n }\n // targetOrigin is the widget's exact origin \u2014 never '*'. A '*' here would\n // broadcast the customer's page content to whatever happens to be listening.\n this.iframe?.contentWindow?.postMessage(envelope(msg), this.config.origin);\n };\n\n private flush() {\n const pending = this.queue;\n this.queue = [];\n for (const m of pending) this.send(m);\n }\n\n /** Tear down: stop listening and remove the host element. For the React wrapper's\n * unmount \u2014 the vanilla `<script>` loader lives for the page's lifetime and never\n * calls this. */\n destroy() {\n window.removeEventListener('message', this.onMessage);\n this.hostEl?.remove();\n this.hostEl = null;\n this.iframe = null;\n this.shadow = null;\n this.ready = false;\n }\n}\n\n/**\n * Programmatic entry \u2014 mount the widget from a config object instead of the DOM\n * `<script data-*>`. This is what the React wrapper (`@matterfact/embed/react`) drives;\n * the vanilla loader below reads the script tag and calls this same class.\n */\nexport function mount(config: LoaderConfig): EmbedHost {\n const host = new EmbedHost(config);\n host.mount();\n return host;\n}\n\nexport { EmbedHost, CHANNEL, readConfig };\n", "/**\n * The vanilla `<script>` loader entry \u2014 the browser stub hosted on a CDN and dropped\n * onto any page:\n *\n * <script src=\"https://cdn.matterfact.com/embed.js\" data-key=\"pk_live_\u2026\" defer></script>\n *\n * This is the ONLY module with the DOM auto-run side-effect. The reusable core\n * (`./loader`), the npm `.` entry (`./index`), and the React wrapper (`./react`) never\n * import it, so they stay SSR-safe \u2014 importing them touches no `document`.\n */\nimport { mount, readConfig } from './loader';\n\nconst config = readConfig();\nif (config) {\n const boot = () => mount(config);\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', boot, { once: true });\n } else {\n boot();\n }\n}\n"],
|
|
5
|
-
"mappings": "AAwBO,IAAMA,EAAU,WAsPhB,SAASC,EAAYC,EAAYC,EAA0B,CAChE,MAAO,CACL,QAASH,EACT,SAAU,EACV,GAAIG,EAAK,CAAE,GAAAA,CAAG,EAAI,CAAC,EACnB,QAAAD,CACF,CACF,CAEO,SAASE,EAAWC,EAA0C,CACnE,OACE,OAAOA,GAAS,UAChBA,IAAS,MACRA,EAA+B,UAAYL,CAEhD,
|
|
6
|
-
"names": ["CHANNEL", "envelope", "payload", "id", "isEnvelope", "data", "DEFAULT_ORIGIN", "devRequested", "readConfig", "el", "publishableKey", "sel", "container", "POS_KEY", "EmbedHost", "config", "event", "isEnvelope", "msg", "m", "envelope", "host", "style", "iframe", "rect", "dx", "dy", "maxRight", "maxBottom", "right", "bottom", "raw", "p", "pos", "provider", "token", "pending", "mount", "config", "readConfig", "boot", "mount"]
|
|
4
|
+
"sourcesContent": ["/**\n * The matterfact embed bridge protocol.\n *\n * This is the contract between the HOST PAGE (a customer's site, running our\n * loader) and the WIDGET (our chat, running in a cross-origin iframe on\n * app.matterfact.com).\n *\n * Two things to understand before changing anything here:\n *\n * 1. THE IFRAME CANNOT SEE THE PAGE. It is cross-origin \u2014 that is the entire\n * point of it. So every fact about the host page (its URL, its DOM, what the\n * user just did) reaches the agent only because the LOADER, which runs as\n * ordinary page JS and *can* see it, chose to send it. The loader is the eye;\n * the widget is the mouth.\n *\n * 2. THIS CONTRACT OUTLIVES THE IFRAME. The next tier is an in-page React SDK\n * with no iframe at all \u2014 and it will speak exactly this. If the message\n * shapes are right, \"deeper integration\" is a transport swap (postMessage ->\n * direct call), not a rewrite. So model the DOMAIN here, not the plumbing.\n */\n\nexport const PROTOCOL_VERSION = 1;\n\n/** Every message is namespaced so we never collide with the host page's own postMessage traffic. */\nexport const CHANNEL = 'mf-embed';\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * A handle on a real element in the host page.\n *\n * Format and semantics are lifted from Playwright's ARIA snapshot (`ref=e12`),\n * for a specific reason: it is the element-handle syntax the frontier models have\n * seen most, via playwright-mcp. We are not being original here on purpose.\n *\n * The ref is an in-page expando plus a snapshot-scoped Map \u2014 never an attribute,\n * so it is invisible to the host page's CSS, its serialization, and its own\n * mutation observers. It is resolved back to an element by the LOADER; the agent\n * never touches the DOM, and never learns a selector.\n */\nexport type ElementRef = string; // 'e12'\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 host \u2192 widget \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** Ambient facts about the page. Cheap, sent on every navigation. */\nexport interface PageContext {\n url?: string;\n /** A route PATTERN ('/orders/:id') beats a raw path \u2014 it tells the agent what KIND of page this is. */\n route?: string;\n path?: string;\n title?: string;\n locale?: string;\n /** 1\u20132 sentences, written the way you'd brief a colleague. The highest-value field by far. */\n description?: string;\n /** Things the page is about. These also become @-mentionable in the composer, for free. */\n entities?: PageEntity[];\n /** Allowlisted only. Never a dump of app state. */\n data?: Record<string, unknown>;\n}\n\nexport interface PageEntity {\n /** Host kinds are namespaced (`x:ticker`) so they can never collide with matterfact's own. */\n kind: string;\n id: string;\n label: string;\n /** Pre-rendered, agent-readable. Keep it short. */\n text?: string;\n data?: Record<string, unknown>;\n}\n\n/** A co-embedded artifact's read-only capability, for the backend to materialize its\n * data. Backend-only \u2014 never rendered. `token` is the artifact's own embed token. */\nexport interface ArtifactGrant {\n id: string;\n owner: string;\n token: string;\n}\n\n/**\n * A snapshot of the page as the agent sees it.\n *\n * `yaml` is Playwright's ARIA-snapshot rendering \u2014 role, accessible name, state,\n * and a ref on anything interactable:\n *\n * - heading \"Orders\" [level=1]\n * - textbox \"Search orders\" [ref=e5]\n * - button \"Export CSV\" [ref=e9]\n *\n * NOT raw HTML. A real page is tens of thousands of tokens of div soup, it gives\n * the model no handle to act with, and it is a prompt-injection firehose. The\n * a11y tree is a tenth the size and is the only signal that survives in-page \u2014\n * `getEventListeners()` is DevTools-only, so listener-sniffing (the browser-use\n * approach) cannot see a single React handler on a real customer's app.\n */\nexport interface DomSnapshot {\n yaml: string;\n /** Monotonic. A ref is only valid within the snapshot that minted it. */\n seq: number;\n /** True when the walk hit its node budget and stopped. The agent must be told it is not seeing everything. */\n truncated: boolean;\n}\n\n/**\n * Where the user's attention is RIGHT NOW.\n *\n * This is the difference between an assistant that can read your page and one that\n * knows what you're doing. A full DOM snapshot answers \"what is on this screen\"; this\n * answers \"what are you looking at and working in\" \u2014 which is what a colleague\n * leaning over reads first. It is small, so it rides on every turn, where the full\n * snapshot does not.\n *\n * Every field here is a LABEL or a REF, never a value. `selection` is the sharpest\n * intent signal there is (\"this is the thing I'm asking about\"), and for exactly that\n * reason it is also where a user might have highlighted their own email \u2014 so it is\n * redacted and honours data-mf-private like everything else.\n */\nexport interface FocusContext {\n /** Text the user has selected. The single strongest \"I'm asking about this\" signal. Redacted. */\n selection?: string;\n /** The control the user is working IN \u2014 by label and ref, never its contents. */\n focused?: { ref?: ElementRef; label: string; role: string };\n /** The refs currently in the viewport: the handful of things actually on screen, out of the whole tree. */\n visibleRefs?: ElementRef[];\n /** How far down the page they are, 0\u20131. A cheap proxy for \"which part am I reading\". */\n scroll?: number;\n}\n\n/** Something the user did. Shaped after PostHog's autocapture \u2014 one readable line, not a replay frame. */\nexport interface ActivityEvent {\n seq: number;\n ts: number;\n type: 'nav' | 'click' | 'input' | 'submit' | 'selection' | 'custom';\n /** Human-readable: 'clicked button \"Export CSV\"'. Semantic, not coordinates. */\n summary: string;\n ref?: ElementRef;\n data?: Record<string, unknown>;\n}\n\n/**\n * A tool the HOST page exposes to the agent.\n *\n * Deliberately shaped as a superset of WebMCP (`navigator.modelContext`, W3C\n * WebML CG draft / Chrome origin trial). A customer who adopts WebMCP should be\n * able to hand us their existing tool declarations unchanged.\n */\nexport interface HostTool {\n name: string;\n description: string;\n /** JSON Schema. */\n inputSchema: Record<string, unknown>;\n /**\n * A read-only tool may run without asking. Anything that MUTATES the page\n * requires the user to confirm, every time \u2014 see the note on ToolCall.\n */\n readOnly?: boolean;\n}\n\nexport type HostToWidget =\n | { type: 'host.ready'; protocol: number; origin: string }\n | { type: 'host.context'; context: PageContext }\n | { type: 'host.focus'; focus: FocusContext }\n | { type: 'host.snapshot'; snapshot: DomSnapshot }\n | { type: 'host.region'; ref: ElementRef; yaml: string }\n | { type: 'host.activity'; events: ActivityEvent[] }\n | { type: 'host.artifactGrants'; grants: ArtifactGrant[] }\n | { type: 'host.tools'; tools: HostTool[] }\n | {\n type: 'host.toolResult';\n callId: string;\n ok: boolean;\n result?: unknown;\n error?: string;\n }\n | { type: 'host.auth'; token: string; expiresAt: number }\n | { type: 'host.theme'; mode: 'light' | 'dark' };\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 widget \u2192 host \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * The agent asking the host to do something.\n *\n * THE SECURITY MODEL, stated once: the page's content is UNTRUSTED. Text on the\n * page can try to instruct the agent, and the moment the agent can act, that stops\n * being a bad answer and becomes a bad ACTION. So:\n *\n * - v1 is READ-ONLY. `snapshot` and `activity` flow; no tool mutates the page.\n * - A tool that is not `readOnly` must be confirmed by the USER, every call. Not\n * \"unless the host opts out\" \u2014 every call. The trigger may have been written by\n * the page.\n * - The host is the enforcement point, not the widget. The widget can be lied to;\n * the loader runs in the page and decides what actually happens.\n */\nexport interface ToolCall {\n callId: string;\n name: string;\n args: Record<string, unknown>;\n}\n\nexport type WidgetToHost =\n | { type: 'widget.ready'; protocol: number }\n /**\n * Ask for the FULL page snapshot. This is the agent PULLING detail, not us pushing\n * it: the focus context rides on every turn, but the whole tree is fetched only\n * when the agent decides it needs to look \u2014 cheaper, and it reads what's relevant\n * to the question instead of drowning in the footer nav every turn.\n */\n | { type: 'widget.requestSnapshot' }\n /** Zoom in: the a11y sub-tree under one ref (a table, a form, a card the agent cares about). */\n | { type: 'widget.readRegion'; ref: ElementRef }\n | { type: 'widget.callTool'; call: ToolCall }\n /** Chat opened/closed \u2014 the loader resizes the iframe and starts/stops observing. */\n | { type: 'widget.setOpen'; open: boolean }\n | { type: 'widget.resize'; height: number }\n /**\n * Maximize / restore. Expanded makes the iframe fill the viewport (with a small\n * margin) so the composer's `/` picker, mention previews, and the transcript have\n * room the corner popup can't give them. The loader owns the iframe size, so only\n * it can do this \u2014 `widget.resize` (height-only) can't widen the popup.\n */\n | { type: 'widget.setExpanded'; expanded: boolean }\n /**\n * Launcher drag. The widget tracks the gesture; the host only moves the element.\n *\n * It has to be this way round, and the reason is easy to get wrong: a press that starts\n * inside an iframe is implicitly captured by that iframe, so every pointermove and the\n * pointerup belong to the widget's document until the button comes up. The host cannot\n * see them at all \u2014 not even through an overlay of its own, because capture beats hit\n * testing. So the host cannot take over a drag mid-gesture; it can only be told.\n *\n * `dx`/`dy` are deltas in SCREEN coordinates, which is the other half of the trick:\n * client coordinates are measured against the iframe's own viewport, and the iframe is\n * being moved under the cursor as the drag proceeds \u2014 so the pointer would appear to\n * stop moving and the launcher would stall after one step. Screen coordinates are\n * absolute and immune to that feedback loop.\n */\n | { type: 'widget.dragStart' }\n | { type: 'widget.dragMove'; dx: number; dy: number }\n | { type: 'widget.dragEnd' }\n /**\n * Grow/shrink the iframe to fit the launcher's context menu. The collapsed launcher is\n * only ~64px tall, so a menu rendered inside it would be clipped by the iframe's own\n * bounds \u2014 the host has to make room before it can be seen. `widget.resize` can't do\n * this: it's height-only AND ignored while closed.\n */\n | { type: 'widget.setMenu'; open: boolean; height: number }\n /** Put the launcher back in the default corner and forget the dragged position. */\n | { type: 'widget.resetPos' }\n /** Get out of the way until the page reloads (a menu action, not a setting). */\n | { type: 'widget.hide' }\n /** The widget has no session; the host must run the hosted-login popup. */\n | { type: 'widget.needsAuth' };\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 envelope \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Everything on the wire is wrapped.\n *\n * `channel` keeps us out of the host page's own postMessage traffic (and out of\n * every other widget's). The receiver ALSO checks `event.origin` against an\n * allowlist and `event.source` against the expected window, on every single\n * message \u2014 a namespace is not a security boundary, it is a politeness.\n */\nexport interface Envelope<T> {\n channel: typeof CHANNEL;\n protocol: number;\n /** Correlates a response to its request; absent for notifications. */\n id?: string;\n payload: T;\n}\n\nexport function envelope<T>(payload: T, id?: string): Envelope<T> {\n return {\n channel: CHANNEL,\n protocol: PROTOCOL_VERSION,\n ...(id ? { id } : {}),\n payload,\n };\n}\n\nexport function isEnvelope(data: unknown): data is Envelope<unknown> {\n return (\n typeof data === 'object' &&\n data !== null &&\n (data as { channel?: unknown }).channel === CHANNEL\n );\n}\n", "import {\n CHANNEL,\n PROTOCOL_VERSION,\n envelope,\n isEnvelope,\n type HostToWidget,\n type WidgetToHost,\n} from './protocol';\n\n/**\n * The matterfact embed loader.\n *\n * <script src=\"https://cdn.matterfact.com/embed.js\"\n * data-key=\"pk_live_acme_...\"\n * defer></script>\n *\n * This file runs on EVERY page load of a customer's site, so it is deliberately\n * tiny and deliberately dumb:\n *\n * - zero dependencies\n * - it does NOT read the DOM. The snapshot/activity code is a separate chunk,\n * fetched only when the user actually opens the chat. A customer should pay\n * nothing for a widget nobody clicked.\n * - it does NOT bundle React, or a CSS framework, or an RPC library.\n *\n * `iframe-resizer` is the thing you will be tempted to reach for here. It is\n * GPL-3.0 and cannot ship in this file. The ResizeObserver bridge below is the\n * fifteen lines it would have cost you anyway.\n */\n\n/** Returns a token this matterfact deployment's auth provider trusts (Firebase idToken,\n * Entra token, \u2026). May be async; return null when there's no signed-in user. */\nexport type AuthTokenProvider = () => string | null | Promise<string | null>;\n\nexport interface LoaderConfig {\n publishableKey: string;\n /** Origin of the widget. Overridable for dev/self-hosted; defaults to production. */\n origin: string;\n theme: 'light' | 'dark' | 'auto';\n /** Optional label identifying THIS embedding, when one app embeds the agent in more\n * than one place (e.g. \"orders\" vs \"support\"). Stamped on runs/threads so usage and\n * history can be told apart per surface. Free-form; the app_id (from the session)\n * is the trusted half. */\n surface: string;\n /**\n * OPTIONAL host-auth passthrough, for TRUSTED first-party embeds (the admin portal,\n * EMC). When set, the host page already holds a token this deployment's auth provider\n * trusts (its Firebase idToken, an Entra token, \u2026); the loader hands it to the widget\n * on `widget.needsAuth` instead of opening a sign-in popup. The backend still verifies\n * the token, so identity can't be forged \u2014 this only skips a redundant second sign-in.\n * Called on demand (so tokens can refresh). Absent \u21D2 the popup/inline sign-in flow.\n * The `<script>` loader has no config here; it reads window.matterfact.getEmbedAuthToken\n * instead (see provideAuth).\n */\n authTokenProvider?: AuthTokenProvider;\n /**\n * Render INTO this element instead of floating in the corner \u2014 for a host that has its\n * own side panel, tool drawer or tab and wants the agent to live there.\n *\n * This inverts who owns the chrome. In corner mode the widget owns everything: it draws\n * its own launcher and it tells us how big to be (setOpen/setExpanded/resize). Inside\n * someone else's panel, both are theirs \u2014 a widget that resized its host's drawer, or\n * drew a second floating bubble inside it, is just broken. So here we fill the\n * container, ignore the size messages, and the widget skips the launcher and renders\n * the chat directly.\n *\n * The host also owns visibility: showing and hiding their own panel IS the open/close\n * control, so there is nothing for us to add.\n */\n container?: HTMLElement | null;\n /**\n * Turn off ALL host-page observation \u2014 no `host.context`, no `host.focus`, no\n * `host.snapshot`, no `host.activity`, no `host.artifactGrants`. Not a filter on what\n * gets sent: when this is false the loader never installs the DOM/nav/focus/activity\n * observers in the first place, and an inbound `widget.requestSnapshot` is ignored\n * rather than answered. Default `true` \u2014 seeing the page is the widget's whole value\n * proposition; this is the escape hatch for a host that wants agent chat with nothing\n * about the page ever reaching it.\n */\n pageContext?: boolean;\n /**\n * Force dev mode (see `devRequested()` below) without needing `?mfdev=1` on the host\n * URL. This is the programmatic equivalent of that trigger, not a replacement for it \u2014\n * the URL param still works untouched; `mount()` ORs the two together.\n */\n dev?: boolean;\n}\n\nconst DEFAULT_ORIGIN = 'https://app.matterfact.com';\n\n/**\n * Has someone asked to see what the widget is doing? `?mfdev=1` on the HOST page.\n *\n * Driven by the host's own URL rather than a `data-` attribute on purpose: an engineer\n * debugging a page they didn't write can add a query param, but they cannot redeploy the\n * customer's site to change a script tag. It's also ephemeral \u2014 it lasts exactly as long\n * as that URL, so nobody can leave it on by accident.\n *\n * This only surfaces what the widget already collects FROM THE PAGE IT'S ON, to the\n * person whose page it is. It grants no access: the session, the origin allowlist and\n * the route scope are all enforced server-side and none of them consult this.\n */\nfunction devRequested(): boolean {\n try {\n return new URLSearchParams(location.search).get('mfdev') === '1';\n } catch {\n return false;\n }\n}\n\nfunction readConfig(): LoaderConfig | null {\n // `document.currentScript` is null inside a module or after async execution, so\n // fall back to finding our own tag by src.\n const el =\n (document.currentScript as HTMLScriptElement | null) ??\n document.querySelector<HTMLScriptElement>('script[data-key][src*=\"embed\"]');\n\n const publishableKey = el?.dataset.key;\n if (!publishableKey) {\n console.error('[matterfact] missing data-key on the embed script tag');\n return null;\n }\n // `data-container=\"#panel\"` renders into the host's own element instead of the\n // corner. A selector rather than an element, because a script tag can't hand us a\n // reference \u2014 and if it doesn't resolve we fall back to the corner rather than\n // vanish: a widget nobody can find looks identical to a broken install.\n const sel = el?.dataset.container;\n const container = sel ? document.querySelector<HTMLElement>(sel) : null;\n if (sel && !container) {\n console.error(\n `[matterfact] data-container=\"${sel}\" matched nothing; falling back to the corner`,\n );\n }\n\n // `data-page-context=\"off\"` (also \"false\" / \"0\") disables all page observation.\n // Anything else \u2014 including the attribute being absent \u2014 leaves it on. Lowercased\n // once before comparing: a privacy toggle that silently stays ON for \"Off\" or\n // \"FALSE\" (a customer's templating/CMS can easily produce either, unintentionally)\n // is exactly the wrong direction for this to fail in.\n const pageContextAttr = el?.dataset.pageContext?.toLowerCase();\n\n return {\n publishableKey,\n origin: el?.dataset.origin || DEFAULT_ORIGIN,\n theme: (el?.dataset.theme as LoaderConfig['theme']) || 'auto',\n surface: el?.dataset.surface || '',\n container,\n pageContext:\n pageContextAttr !== 'off' &&\n pageContextAttr !== 'false' &&\n pageContextAttr !== '0',\n // No `data-dev` \u2014 see the `dev` field's doc comment: the URL trigger is the\n // point for the script-tag path, so there is deliberately no script-tag knob here.\n };\n}\n\n/** Where the user dragged the launcher, in px from the viewport's bottom-right. */\ninterface DragPos {\n right: number;\n bottom: number;\n}\n\nconst POS_KEY = 'mf.embed.pos';\n\nclass EmbedHost {\n private iframe: HTMLIFrameElement | null = null;\n private shadow: ShadowRoot | null = null;\n /** Buffered until the widget says it's listening \u2014 postMessage before load is dropped silently. */\n private queue: HostToWidget[] = [];\n private ready = false;\n private open = false;\n private expanded = false;\n /** Null until the user drags; then it pins the corner offset and survives reloads. */\n private pos: DragPos | null = null;\n /** Where the launcher sat when the current drag began; deltas are applied to this. */\n private dragBase: DragPos | null = null;\n /** Loaded on first open. Holds everything that touches the customer's DOM. */\n private context: Promise<typeof import('./context')> | null = null;\n /** The host element; kept so `destroy()` can remove it (React lifecycle). */\n private hostEl: HTMLDivElement | null = null;\n /** Rendering into the host's own element: they own the box, the chrome and visibility. */\n private readonly inline: boolean;\n\n constructor(private config: LoaderConfig) {\n this.inline = !!config.container;\n }\n\n mount() {\n // A CLOSED shadow root, on a container that resets every inherited property.\n //\n // We are a guest on someone else's page. Their CSS must not reach into us, our\n // CSS must not leak out, and their JS should not be able to walk into our tree\n // by accident (closed mode: `host.shadowRoot` is null). `contain` stops our\n // layout/paint from invalidating theirs.\n const host = document.createElement('div');\n this.hostEl = host;\n host.id = 'matterfact-embed';\n\n if (this.inline) {\n // The container's box IS the widget's box. No fixed positioning, no z-index\n // scramble, no drag: where this sits is the host's layout problem, which is the\n // entire point of asking for it.\n host.style.cssText = [\n 'all: initial',\n 'position: relative',\n 'display: block',\n 'width: 100%',\n 'height: 100%',\n 'contain: layout style',\n ].join(';');\n this.config.container!.appendChild(host);\n } else {\n this.pos = this.readPos();\n host.style.cssText = [\n 'all: initial',\n 'position: fixed',\n `right: ${this.pos ? this.pos.right : 20}px`,\n `bottom: ${this.pos ? this.pos.bottom : 20}px`,\n // Below the max so a host that genuinely needs to cover us (a modal, a cookie\n // banner they are legally obliged to show) still can.\n 'z-index: 2147483000',\n 'contain: layout style',\n ].join(';');\n document.body.appendChild(host);\n }\n\n this.shadow = host.attachShadow({ mode: 'closed' });\n\n const style = document.createElement('style');\n // Shared prefix, then only what differs. This ships on every page load and the stub\n // has ~no headroom, so the two modes must not each carry a whole stylesheet.\n //\n // Inline fills the host's box and adds nothing: no radius, no shadow. Their panel\n // already has whatever chrome they chose; ours would sit inside it looking like a\n // mistake.\n style.textContent =\n ':host{all:initial}iframe{border:0;display:block;color-scheme:light dark;}' +\n (this.inline\n ? 'iframe{width:100%;height:100%}'\n : // Hairline ring + soft ambient: the widget must read as a crisp card on\n // ANY host background, including pure white where a shadow alone bleeds.\n 'iframe{border-radius:12px;box-shadow:0 0 0 1px #00000014,0 8px 40px #00000029;width:400px;' +\n 'height:64px;transition:height .18s ease,width .18s ease}' +\n 'iframe[data-open=\"true\"]{width:420px;height:640px}' +\n // Expanded: a full-height SIDE PANEL docked to the host's right edge, not a\n // viewport-covering overlay \u2014 room for the composer's slash-picker and mention\n // previews, capped to the viewport on narrow screens.\n 'iframe[data-open=\"true\"][data-expanded=\"true\"]{width:min(600px,calc(100vw - 40px));' +\n 'height:calc(100vh - 40px)}');\n this.shadow.appendChild(style);\n\n const iframe = document.createElement('iframe');\n iframe.title = 'matterfact assistant';\n //\n // `allow-same-origin` is REQUIRED, and leaving it out is the trap.\n //\n // Without it the framed document gets an OPAQUE origin: its postMessage arrives\n // as `event.origin === \"null\"`, so our own origin check rejects the handshake and\n // the bridge silently never connects. It also denies the widget any storage at\n // all \u2014 no session, no auth, ever.\n //\n // The familiar warning \u2014 \"allow-scripts + allow-same-origin lets the frame escape\n // its sandbox\" \u2014 is about a frame that is SAME-ORIGIN WITH THE FRAMER, which can\n // then reach up and delete its own sandbox attribute. Ours is cross-origin to the\n // host by construction (that is the entire security model), so it cannot touch\n // this element. What the sandbox still buys us is real: no top-level navigation,\n // no downloads, no pointer lock.\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox',\n );\n // Dictation needs an explicit permissions-policy grant: without `allow`,\n // getUserMedia inside the frame is hard-blocked no matter what the user\n // approves. The bare token scopes the grant to the iframe's own origin\n // (the app), not the host page. A host page can still deny the feature\n // via its own Permissions-Policy response header \u2014 outside our control.\n iframe.setAttribute('allow', 'microphone');\n iframe.src =\n `${this.config.origin}/embed/chat?k=${encodeURIComponent(\n this.config.publishableKey,\n )}&o=${encodeURIComponent(location.origin)}` +\n (this.config.surface\n ? `&s=${encodeURIComponent(this.config.surface)}`\n : '') +\n // Either trigger works: the URL param (no redeploy needed) OR the config's\n // programmatic `dev` (the React prop). See both doc comments above.\n (devRequested() || this.config.dev ? '&dev=1' : '') +\n (this.inline ? '&inline=1' : '');\n this.iframe = iframe;\n this.shadow.appendChild(iframe);\n\n window.addEventListener('message', this.onMessage);\n }\n\n /**\n * Every message is checked twice, on every single message \u2014 not once at setup.\n *\n * `channel` is a namespace, not a boundary. The origin and source checks are the\n * boundary: any frame on the page can postMessage us, and a page with an ad iframe\n * on it has plenty of frames.\n */\n private onMessage = (event: MessageEvent) => {\n if (event.origin !== this.config.origin) return;\n if (event.source !== this.iframe?.contentWindow) return;\n if (!isEnvelope(event.data)) return;\n\n const msg = event.data.payload as WidgetToHost;\n\n switch (msg.type) {\n case 'widget.ready':\n this.ready = true;\n this.send({\n type: 'host.ready',\n protocol: PROTOCOL_VERSION,\n origin: location.origin,\n });\n this.flush();\n // Inline has no \"open\" event to hang this off \u2014 the chat is visible the moment\n // the host renders their panel, so the eye has to load now or the agent is\n // blind to the page for the whole session. The corner keeps its lazy load: a\n // page whose visitors never click still pays nothing.\n if (this.inline) void this.loadContext();\n break;\n\n case 'widget.setOpen':\n // Inline: the host's panel IS the open/close control. There's no popup to size.\n if (this.inline) break;\n this.open = msg.open;\n this.iframe?.setAttribute('data-open', String(msg.open));\n // Closing the popup always restores it \u2014 a widget that reopens should start\n // at the corner size, not wherever it was maximized to last time.\n if (!msg.open) {\n this.expanded = false;\n this.iframe?.setAttribute('data-expanded', 'false');\n }\n // The DOM code is fetched HERE \u2014 the first time someone actually opens the\n // chat \u2014 and never on a page where they don't.\n if (msg.open) void this.loadContext();\n break;\n\n case 'widget.setExpanded':\n // Inline: \"maximize\" would mean resizing someone else's panel from inside it.\n if (this.inline) break;\n this.expanded = msg.expanded;\n this.iframe?.setAttribute('data-expanded', String(msg.expanded));\n // A prior widget.resize set an inline height; clear it so the maximized CSS\n // (and, on restore, the popup CSS) wins.\n if (this.iframe) this.iframe.style.height = '';\n break;\n\n case 'widget.resize':\n // Inline: the container's height is the host's business, and an auto-grow here\n // would fight their layout every time the transcript got longer.\n if (this.inline) break;\n // Height auto-grow is for the corner popup only; when maximized the CSS owns\n // the size, so don't let a resize shrink it back.\n if (this.iframe && this.open && !this.expanded) {\n this.iframe.style.height = `${Math.min(msg.height, window.innerHeight - 40)}px`;\n }\n break;\n\n case 'widget.requestSnapshot':\n // pageContext: false \u21D2 `sendSnapshot` itself no-ops (see context.ts) rather\n // than gating here \u2014 this file is the size-budgeted stub, and the check\n // costs nothing extra in the lazy chunk that already owns the DOM read.\n void this.loadContext().then((m) => m.sendSnapshot(this.send));\n break;\n\n case 'widget.readRegion':\n void this.loadContext().then((m) => m.sendRegion(msg.ref, this.send));\n break;\n\n case 'widget.callTool':\n void this.loadContext().then((m) => m.callTool(msg.call, this.send));\n break;\n\n // Everything below is LAUNCHER chrome: there is no launcher inline (the widget\n // doesn't draw one), and moving or hiding the host's own panel from inside it\n // would be us redecorating their app. An older cached loader could still be told\n // any of these by a newer widget, so they're guarded rather than assumed absent.\n case 'widget.dragStart':\n if (this.inline) break;\n this.dragBase = this.cornerOffset();\n break;\n\n case 'widget.dragMove':\n if (this.inline) break;\n this.dragTo(msg.dx, msg.dy);\n break;\n\n case 'widget.dragEnd':\n if (this.inline) break;\n this.dragBase = null;\n this.writePos(this.pos);\n break;\n\n case 'widget.setMenu':\n if (this.inline) break;\n // Make room for the launcher's menu. Only meaningful while collapsed \u2014 open,\n // the popup is already taller than any menu.\n if (this.iframe && !this.open) {\n this.iframe.style.height = msg.open ? `${64 + msg.height}px` : '';\n }\n break;\n\n case 'widget.resetPos':\n if (this.inline) break;\n this.resetPos();\n break;\n\n case 'widget.hide':\n // Inline: hiding is the host's panel to hide. Blanking their drawer from in\n // here would leave them with an empty box and no way to get it back.\n if (this.inline) break;\n if (this.hostEl) this.hostEl.style.display = 'none';\n break;\n\n case 'widget.needsAuth':\n void this.provideAuth();\n break;\n }\n };\n\n /**\n * Own a drag for its lifetime.\n *\n * The widget reports the press and then goes quiet: a cross-origin iframe only gets\n * pointer events while the pointer is over it, and a drag leaves that box immediately.\n * So we lay a transparent layer over the whole viewport and track the gesture in the\n * host document, where it can't be lost. The layer also stops the pointer landing on\n * the customer's own UI mid-drag (text selection, hover states, stray clicks).\n *\n * We are the dumb half on purpose \u2014 see `widget.dragMove` in the protocol for why the\n * widget has to own the gesture. All we do is take a delta and place the element.\n */\n private cornerOffset(): DragPos {\n const rect = this.hostEl!.getBoundingClientRect();\n return {\n right: window.innerWidth - rect.right,\n bottom: window.innerHeight - rect.bottom,\n };\n }\n\n private dragTo(dx: number, dy: number) {\n if (!this.dragBase || !this.hostEl) return;\n const rect = this.hostEl.getBoundingClientRect();\n // Clamp to the viewport: the position persists, so letting someone drop the launcher\n // off-screen would strand it there across reloads with no way back to it.\n const maxRight = Math.max(0, window.innerWidth - rect.width);\n const maxBottom = Math.max(0, window.innerHeight - rect.height);\n const right = Math.min(Math.max(0, this.dragBase.right - dx), maxRight);\n const bottom = Math.min(Math.max(0, this.dragBase.bottom - dy), maxBottom);\n this.pos = { right, bottom };\n this.hostEl.style.right = `${right}px`;\n this.hostEl.style.bottom = `${bottom}px`;\n }\n\n /** Reset to the default corner (a menu action \u2014 the drag is otherwise sticky). */\n private resetPos() {\n this.pos = null;\n this.writePos(null);\n if (this.hostEl) {\n this.hostEl.style.right = '20px';\n this.hostEl.style.bottom = '20px';\n }\n }\n\n private readPos(): DragPos | null {\n // First-party storage on the CUSTOMER's origin, so each site remembers its own spot.\n // Never throws: storage is unavailable in some embedding contexts, and a widget that\n // can't remember where it was put is fine \u2014 one that fails to mount is not.\n try {\n const raw = localStorage.getItem(POS_KEY);\n if (!raw) return null;\n const p = JSON.parse(raw) as Partial<DragPos>;\n return typeof p?.right === 'number' && typeof p?.bottom === 'number'\n ? { right: p.right, bottom: p.bottom }\n : null;\n } catch {\n return null;\n }\n }\n\n private writePos(pos: DragPos | null) {\n try {\n if (pos) localStorage.setItem(POS_KEY, JSON.stringify(pos));\n else localStorage.removeItem(POS_KEY);\n } catch {\n /* storage denied \u2014 the position just won't survive the reload */\n }\n }\n\n /**\n * Answer `widget.needsAuth`. If a trusted first-party host has an auth-token provider,\n * call it and hand the token straight to the widget via `host.auth` \u2014 no popup. The\n * provider comes from EITHER the programmatic config (the React `<MatterfactAgent\n * getAuthToken>` prop) OR a global the host page sets for the `<script>` loader:\n *\n * window.matterfact = { getEmbedAuthToken: () => getIdToken(user) };\n *\n * Read fresh at call time (not at readConfig), so a global set after the loader booted\n * \u2014 e.g. once the host's auth is ready \u2014 is still picked up. Otherwise fall back to the\n * hosted-login popup. `expiresAt: 0`: the widget doesn't cache it, it exchanges the\n * token for a rotating embed session anyway.\n */\n private async provideAuth() {\n const provider =\n this.config.authTokenProvider ??\n (globalThis as { matterfact?: { getEmbedAuthToken?: AuthTokenProvider } })\n .matterfact?.getEmbedAuthToken;\n if (provider) {\n try {\n const token = await provider();\n if (token) {\n this.send({ type: 'host.auth', token, expiresAt: 0 });\n return;\n }\n } catch {\n /* fall through to the popup */\n }\n }\n void this.loadContext().then((m) => m.beginAuth(this.config, this.send));\n }\n\n private loadContext() {\n // One chunk, one fetch, cached. Everything that can see the customer's page\n // lives behind this boundary.\n this.context ??= import('./context').then((m) => {\n // The single place the eye actually starts: when pageContext is off, `start()`\n // skips installing every DOM/nav/focus/activity observer \u2014 not a filter over\n // what gets sent afterward, nothing is collected in the first place. Passed\n // through raw: `start`'s default parameter is what turns `undefined` (the\n // option omitted) into \"on\".\n m.start(this.send, this.config.origin, this.config.pageContext);\n // start() emits the OS-preference theme. An explicit data-theme on the\n // script tag is the host's choice \u2014 resend it so it wins over auto-detect\n // (a light-branded site must be able to force a light widget on a dark-OS\n // visitor, and vice versa).\n if (this.config.theme !== 'auto') {\n this.send({ type: 'host.theme', mode: this.config.theme });\n }\n return m;\n });\n return this.context;\n }\n\n private send = (msg: HostToWidget) => {\n if (!this.ready) {\n this.queue.push(msg);\n return;\n }\n // targetOrigin is the widget's exact origin \u2014 never '*'. A '*' here would\n // broadcast the customer's page content to whatever happens to be listening.\n this.iframe?.contentWindow?.postMessage(envelope(msg), this.config.origin);\n };\n\n private flush() {\n const pending = this.queue;\n this.queue = [];\n for (const m of pending) this.send(m);\n }\n\n /** Tear down: stop listening and remove the host element. For the React wrapper's\n * unmount \u2014 the vanilla `<script>` loader lives for the page's lifetime and never\n * calls this. */\n destroy() {\n window.removeEventListener('message', this.onMessage);\n this.hostEl?.remove();\n this.hostEl = null;\n this.iframe = null;\n this.shadow = null;\n this.ready = false;\n // context.ts's listeners/history-patch/ref-registry are module-global and\n // outlive this instance \u2014 stop() undoes exactly what start() installed. A no-op\n // if the eye was never loaded (chat never opened, so nothing was ever started).\n // This is the unmount-with-no-remount case; start()'s own stop()-first call\n // (see context.ts) is what protects a REMOUNT, which is why both exist.\n void this.context?.then((m) => m.stop());\n }\n}\n\n/**\n * Programmatic entry \u2014 mount the widget from a config object instead of the DOM\n * `<script data-*>`. This is what the React wrapper (`@matterfact/embed/react`) drives;\n * the vanilla loader below reads the script tag and calls this same class.\n */\nexport function mount(config: LoaderConfig): EmbedHost {\n const host = new EmbedHost(config);\n host.mount();\n return host;\n}\n\nexport { EmbedHost, CHANNEL, readConfig };\n", "/**\n * The vanilla `<script>` loader entry \u2014 the browser stub hosted on a CDN and dropped\n * onto any page:\n *\n * <script src=\"https://cdn.matterfact.com/embed.js\" data-key=\"pk_live_\u2026\" defer></script>\n *\n * This is the ONLY module with the DOM auto-run side-effect. The reusable core\n * (`./loader`), the npm `.` entry (`./index`), and the React wrapper (`./react`) never\n * import it, so they stay SSR-safe \u2014 importing them touches no `document`.\n */\nimport { mount, readConfig } from './loader';\n\nconst config = readConfig();\nif (config) {\n const boot = () => mount(config);\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', boot, { once: true });\n } else {\n boot();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["CHANNEL", "envelope", "payload", "id", "isEnvelope", "data", "DEFAULT_ORIGIN", "devRequested", "readConfig", "el", "publishableKey", "sel", "container", "pageContextAttr", "POS_KEY", "EmbedHost", "config", "event", "isEnvelope", "msg", "m", "envelope", "host", "style", "iframe", "rect", "dx", "dy", "maxRight", "maxBottom", "right", "bottom", "raw", "p", "pos", "provider", "token", "pending", "mount", "config", "readConfig", "boot", "mount"]
|
|
7
7
|
}
|