@matterfact/embed 0.3.0 → 0.5.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.
Files changed (56) hide show
  1. package/README.md +45 -5
  2. package/dist/{chunk-33LPVL2R.js → chunk-GZZYR6YF.js} +3 -3
  3. package/dist/{chunk-33LPVL2R.js.map → chunk-GZZYR6YF.js.map} +3 -3
  4. package/dist/chunk-JN3ZMONO.js +2 -0
  5. package/dist/chunk-JN3ZMONO.js.map +7 -0
  6. package/dist/{chunk-CHPADW72.js → chunk-JSH3BRYP.js} +80 -47
  7. package/dist/chunk-JSH3BRYP.js.map +1 -0
  8. package/dist/{chunk-SQJX27LT.js → chunk-NZIN3LK7.js} +79 -46
  9. package/dist/chunk-NZIN3LK7.js.map +1 -0
  10. package/dist/chunk-Z53V2P4B.js +2 -0
  11. package/dist/context-AQY2LJWK.js +3 -0
  12. package/dist/{context-BFNFFHC2.js.map → context-AQY2LJWK.js.map} +1 -1
  13. package/dist/{context-MORDASRH.js → context-UBTZEEWS.js} +6 -6
  14. package/dist/embed.js +1 -1
  15. package/dist/embed.js.map +3 -3
  16. package/dist/index.cjs +106 -63
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +23 -3
  19. package/dist/index.d.ts +23 -3
  20. package/dist/index.js +23 -17
  21. package/dist/index.js.map +1 -1
  22. package/dist/react.cjs +109 -66
  23. package/dist/react.cjs.map +1 -1
  24. package/dist/react.d.cts +14 -1
  25. package/dist/react.d.ts +14 -1
  26. package/dist/react.js +25 -19
  27. package/dist/react.js.map +1 -1
  28. package/dist/{snapshot-IWVXLE4G.js → snapshot-HYMRZTZC.js} +6 -2
  29. package/dist/snapshot-HYMRZTZC.js.map +1 -0
  30. package/dist/{snapshot-QBV7DTJP.js → snapshot-XFCV2MYR.js} +7 -4
  31. package/dist/snapshot-XFCV2MYR.js.map +1 -0
  32. package/examples/README.md +46 -0
  33. package/examples/demo-host/index.html +163 -0
  34. package/examples/demo-host/serve.mjs +62 -0
  35. package/examples/embed-demo/.env.example +24 -0
  36. package/examples/embed-demo/README.md +72 -0
  37. package/examples/embed-demo/index.html +12 -0
  38. package/examples/embed-demo/package.json +25 -0
  39. package/examples/embed-demo/src/App.tsx +189 -0
  40. package/examples/embed-demo/src/config.ts +43 -0
  41. package/examples/embed-demo/src/main.tsx +10 -0
  42. package/examples/embed-demo/src/styles.css +354 -0
  43. package/examples/embed-demo/tsconfig.json +16 -0
  44. package/examples/embed-demo/vite.config.ts +11 -0
  45. package/examples/host-panel.html +237 -0
  46. package/package.json +3 -2
  47. package/dist/chunk-CHPADW72.js.map +0 -1
  48. package/dist/chunk-F7DLOR7F.js +0 -2
  49. package/dist/chunk-F7DLOR7F.js.map +0 -7
  50. package/dist/chunk-FBIJZJGL.js +0 -2
  51. package/dist/chunk-SQJX27LT.js.map +0 -1
  52. package/dist/context-BFNFFHC2.js +0 -3
  53. package/dist/snapshot-IWVXLE4G.js.map +0 -1
  54. package/dist/snapshot-QBV7DTJP.js.map +0 -1
  55. /package/dist/{chunk-FBIJZJGL.js.map → chunk-Z53V2P4B.js.map} +0 -0
  56. /package/dist/{context-MORDASRH.js.map → context-UBTZEEWS.js.map} +0 -0
@@ -0,0 +1,2 @@
1
+ var c="";var p=null,R=0,l=[],S="",b=!0,g=null,h=null,y=null,x=null,M=[/\b[\w.+-]+@[\w-]+\.[\w.]{2,}\b/g,/\b(?:\d[ -]?){13,19}\b/g,/\b\d{3}[- ]?\d{2}[- ]?\d{4}\b/g,/\b\d{9,}\b/g,/(?:\+?\d{1,2}[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b/g,/\b(?:sk|pk|rk|ak)_(?:live|test)_[A-Za-z0-9]{8,}\b/g,/\beyJ[\w-]+\.[\w-]+\.[\w-]+\b/g];function s(t){let e=t;for(let n of M)e=e.replace(n,"[redacted]");return e}function v(t){if(t.closest("[data-mf-private]"))return!0;if(t.tagName==="INPUT"){let n=t.type;if(n==="password"||n==="hidden")return!0}return!1}function L(t){let e=t.match(/^\/(?:embed\/)?artifacts\/(.+?)\/?$/);return e?decodeURIComponent(e[1]):null}function q(){if(!c)return[];let t=[];for(let e of Array.from(document.querySelectorAll("iframe"))){let n;try{n=new URL(e.getAttribute("src")||"",location.href)}catch{continue}if(n.origin!==c)continue;let r=L(n.pathname);r&&(t.some(o=>o.id===r)||t.push({kind:"artifact",id:r,label:s(e.getAttribute("title")||"")||r}))}return t}function F(){return Array.from(document.querySelectorAll("iframe")).filter(t=>{try{let e=new URL(t.getAttribute("src")||"",location.href);return e.origin!==location.origin&&e.origin!==c}catch{return!1}}).length}function N(){let t=window.matterfact?.context??{},e=q(),n=F();return{url:location.origin+location.pathname,path:location.pathname,title:s(document.title),locale:document.documentElement.lang||void 0,...t,entities:[...t.entities??[],...e],data:{...t.data??{},...n?{opaque_frames:n}:{}}}}function T(){p?.({type:"host.context",context:N()})}function $(t,e){let n=[];for(let r of t){let o;try{o=new URL(r||"",location.href)}catch{continue}if(o.origin!==e)continue;let i=L(o.pathname);if(!i)continue;let a=o.searchParams.get("owner")||"",A=o.searchParams.get("t")||"";!a||!A||n.some(P=>P.id===i)||n.push({id:i,owner:a,token:A})}return n}function U(){if(!c)return[];let t=Array.from(document.querySelectorAll("iframe")).map(e=>e.getAttribute("src")||"");return $(t,c)}function C(){p?.({type:"host.artifactGrants",grants:U()})}function E(t){l.push({...t,seq:++R,ts:Date.now()}),l.length>40&&l.shift(),p?.({type:"host.activity",events:[l[l.length-1]]})}function O(t){let e=t.getAttribute("aria-label");if(e)return e;let n=t.id;if(n){let a=document.querySelector(`label[for="${CSS.escape(n)}"]`)?.textContent?.trim();if(a)return a}let r=t.closest("label")?.textContent?.trim();if(r)return r;let o=t.getAttribute("placeholder");return o||""}var G=new Set(["INPUT","SELECT","TEXTAREA"]);function u(t){let e=t.getAttribute("role")||t.tagName.toLowerCase(),n=t.getAttribute("aria-label")||(G.has(t.tagName)?O(t):t.innerText?.trim().slice(0,60))||t.getAttribute("title")||"";return n?`${e} "${s(n)}"`:e}var _='a[href],button,input,select,textarea,summary,[role="button"],[role="link"],[role="menuitem"],[role="tab"],[role="option"],[role="checkbox"],[role="switch"],[role="radio"],[onclick],[tabindex]';function k(t){let e=t.target;if(!e||!(e instanceof Element))return;let n=e.closest("label"),o=(n?n.getAttribute("for")&&document.getElementById(n.getAttribute("for"))||n.querySelector("input,select,textarea"):null)??e.closest(_);!o||v(o)||E({type:"click",summary:`clicked ${u(o)}`})}function I(t){let e=t.target;!e||v(e)||E({type:"submit",summary:`submitted ${u(e)}`})}function H(t){let e=t.target;if(!e||!(e instanceof Element)||v(e))return;let n=e.tagName,r=e.type;if(n==="INPUT"&&(r==="password"||r==="hidden"))return;let o=`changed ${u(e)}`;if(n==="SELECT"){let i=e.selectedOptions[0]?.text;i&&(o=`${u(e)} \u2192 "${s(i)}"`)}else(r==="checkbox"||r==="radio")&&(o=`${e.checked?"checked":"unchecked"} ${u(e)}`);E({type:"input",summary:o})}function X(){let t=()=>{let e=location.pathname;e!==S&&(S=e,E({type:"nav",summary:`navigated to ${e}`}),T(),C())};g=t;for(let e of["pushState","replaceState"]){let n=history[e];e==="pushState"?h=n:y=n,history[e]=function(...r){let o=n.apply(this,r);return t(),o}}window.addEventListener("popstate",t)}var d={};async function B(){let t={},e=window.getSelection?.();if(e&&!e.isCollapsed){let i=e.anchorNode?.parentElement??null;if(!i||!i.closest("[data-mf-private]")){let a=e.toString().trim().slice(0,500);a&&(t.selection=s(a))}}let n=document.activeElement;if(n&&n!==document.body&&!v(n)&&!n.closest("[data-mf-private]")){let{snapshot:i}=await w();t.focused={label:s(V(n)),role:n.getAttribute("role")||n.tagName.toLowerCase()}}let r=document.documentElement,o=r.scrollHeight-r.clientHeight;return t.scroll=o>0?Math.round(r.scrollTop/o*100)/100:0,t}function V(t){return u(t)}async function w(){let t=await import("./chunk-GZZYR6YF.js");return x=t,t}var f=null;function m(){f||(f=setTimeout(async()=>{f=null,d=await B(),p?.({type:"host.focus",focus:d})},250))}var W=0;async function z(t){if(!b)return;let{snapshot:e}=await w(),{yaml:n,truncated:r,visibleRefs:o}=e();t({type:"host.snapshot",snapshot:{yaml:s(n),seq:++W,truncated:r}}),d={...d,visibleRefs:o},t({type:"host.focus",focus:d})}async function D(t,e){if(!b)return;let{snapshotRegion:n,resolveRef:r}=await w(),o=r(t);if(!o){e({type:"host.region",ref:t,yaml:"(this element is no longer on the page)"});return}let{yaml:i}=n(o);e({type:"host.region",ref:t,yaml:s(i)})}async function J(t,e){e({type:"host.toolResult",callId:t.callId,ok:!1,error:"Host tools are read-only in this version; no action was taken."})}function Y(){document.removeEventListener("click",k,{capture:!0}),document.removeEventListener("submit",I,{capture:!0}),document.removeEventListener("change",H,{capture:!0}),document.removeEventListener("selectionchange",m),document.removeEventListener("focusin",m,{capture:!0}),window.removeEventListener("scroll",m,{capture:!0}),g&&(window.removeEventListener("popstate",g),g=null),h&&(history.pushState=h,h=null),y&&(history.replaceState=y,y=null),f&&(clearTimeout(f),f=null),p=null,l.length=0,d={},c="",x?.clearRefs()}function Z(t,e,n=!0){Y(),p=t,c=e||"",S=location.pathname,b=n,b&&(T(),C(),X(),document.addEventListener("click",k,{capture:!0,passive:!0}),document.addEventListener("submit",I,{capture:!0,passive:!0}),document.addEventListener("change",H,{capture:!0,passive:!0}),document.addEventListener("selectionchange",m,{passive:!0}),document.addEventListener("focusin",m,{capture:!0,passive:!0}),window.addEventListener("scroll",m,{capture:!0,passive:!0}));let r=matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";t({type:"host.theme",mode:r})}export{s as a,v as b,L as c,N as d,$ as e,z as f,D as g,J as h,Y as i,Z as j};
2
+ //# sourceMappingURL=chunk-JN3ZMONO.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/context.ts"],
4
+ "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 \u2014 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 \u2014 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 \u2014 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 \u21D2 the host opted out of ALL page observation \u2014 every\n * exported entry point below that would otherwise read or send the page checks this. */\nlet pageContextOn = true;\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 teardown state \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 below is module-global bookkeeping so `stop()` (see `start()`, bottom of\n * file) can undo exactly what `start()`/`watchNavigation()` installed \u2014 remove every\n * listener, restore `history` to what it was before we wrapped it, and forget any\n * DOM-walk module we pulled in. All of this outlives a single `EmbedHost`; see\n * `stop()`'s doc comment for why that's the bug this exists to close.\n */\n\n/** The `fire` closure `watchNavigation()` handed to `popstate` \u2014 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/** Set once `sendSnapshot`/`sendRegion`/`readFocus` actually pull in the DOM-walk\n * chunk (`./dom/snapshot`) \u2014 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/* \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 redaction \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\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 \u2014 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 \u2014 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/* \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 page context \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 * 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 \u2014 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 \u2014 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 \u2014 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/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 artifact grants (backend-only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\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/* \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 activity \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\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}` \u2014 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 \u2014 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 \u2014 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 \u2014 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 \u2014 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 \u2014 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 \u2014 \"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)} \u2192 \"${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 \u2014 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 \u2014 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/* \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 focal context \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 * 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 \u2014 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 \u2014 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 \u2014 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 \u2014 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 \u2014 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 \u2014\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/* \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 snapshot \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\nlet snapshotSeq = 0;\n\nexport async function sendSnapshot(emit: Send) {\n // pageContext: false \u21D2 no snapshot, ever \u2014 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 \u2014 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/* \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 tools \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 * v1 IS READ-ONLY.\n *\n * The page's content is untrusted \u2014 text on it can try to instruct the agent \u2014 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\" \u2014 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/* \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 stop / start \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 opposite number of `start()` \u2014 remove every listener it (or `watchNavigation`)\n * installed, restore `history.pushState`/`replaceState` to what they were before we\n * wrapped them, and forget the module-level `send`/`activity`/focus state. Nothing\n * here is a filter over what gets sent afterward \u2014 there is simply nothing left\n * 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) \u2014 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 \u2014 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 (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 \u2014 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 \u2014 no declared/found context, no artifact grants, no nav/\n * click/submit/change/focus observers \u2014 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, {\n capture: true,\n passive: true,\n });\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 \u2014 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"],
5
+ "mappings": "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",
6
+ "names": ["widgetOrigin", "send", "activitySeq", "activity", "lastUrl", "pageContextOn", "navFire", "origPushState", "origReplaceState", "snapshotModule", "PII", "redact", "text", "out", "re", "isPrivate", "el", "t", "artifactIdFromPath", "pathname", "m", "embeddedMatterfactEntities", "widgetOrigin", "frame", "u", "id", "e", "opaqueFrameCount", "f", "readPageContext", "declared", "found", "opaque", "publishContext", "grantsFromIframeSrcs", "srcs", "origin", "raw", "owner", "token", "g", "readArtifactGrants", "publishArtifactGrants", "pushActivity", "controlLabel", "aria", "wrapping", "placeholder", "FORM_CONTROLS", "describe", "role", "label", "ACTIONABLE", "onClick", "ev", "target", "actionable", "onSubmit", "onChange", "tag", "type", "summary", "opt", "watchNavigation", "fire", "url", "name", "orig", "args", "r", "lastFocus", "readFocus", "focus", "sel", "anchor", "active", "snapshot", "loadSnapshotModule", "describeControl", "doc", "scrollable", "focusTimer", "scheduleFocus", "snapshotSeq", "sendSnapshot", "emit", "yaml", "truncated", "visibleRefs", "sendRegion", "ref", "snapshotRegion", "resolveRef", "callTool", "call", "stop", "start", "pageContext", "theme"]
7
+ }
@@ -5,6 +5,11 @@ var send = null;
5
5
  var activitySeq = 0;
6
6
  var activity = [];
7
7
  var lastUrl = "";
8
+ var pageContextOn = true;
9
+ var navFire = null;
10
+ var origPushState = null;
11
+ var origReplaceState = null;
12
+ var snapshotModule = null;
8
13
  var PII = [
9
14
  /\b[\w.+-]+@[\w-]+\.[\w.]{2,}\b/g,
10
15
  // email
@@ -191,8 +196,11 @@ function watchNavigation() {
191
196
  publishContext();
192
197
  publishArtifactGrants();
193
198
  };
199
+ navFire = fire;
194
200
  for (const name of ["pushState", "replaceState"]) {
195
201
  const orig = history[name];
202
+ if (name === "pushState") origPushState = orig;
203
+ else origReplaceState = orig;
196
204
  history[name] = function(...args) {
197
205
  const r = orig.apply(this, args);
198
206
  fire();
@@ -214,7 +222,7 @@ async function readFocus() {
214
222
  }
215
223
  const active = document.activeElement;
216
224
  if (active && active !== document.body && !isPrivate(active) && !active.closest("[data-mf-private]")) {
217
- const { snapshot } = await import('./snapshot-QBV7DTJP.js');
225
+ const { snapshot } = await loadSnapshotModule();
218
226
  focus.focused = {
219
227
  label: redact(describeControl(active)),
220
228
  role: active.getAttribute("role") || active.tagName.toLowerCase()
@@ -228,6 +236,11 @@ async function readFocus() {
228
236
  function describeControl(el) {
229
237
  return describe(el);
230
238
  }
239
+ async function loadSnapshotModule() {
240
+ const m = await import('./snapshot-XFCV2MYR.js');
241
+ snapshotModule = m;
242
+ return m;
243
+ }
231
244
  var focusTimer = null;
232
245
  function scheduleFocus() {
233
246
  if (focusTimer) return;
@@ -239,7 +252,8 @@ function scheduleFocus() {
239
252
  }
240
253
  var snapshotSeq = 0;
241
254
  async function sendSnapshot(emit) {
242
- const { snapshot } = await import('./snapshot-QBV7DTJP.js');
255
+ if (!pageContextOn) return;
256
+ const { snapshot } = await loadSnapshotModule();
243
257
  const { yaml, truncated, visibleRefs } = snapshot();
244
258
  emit({
245
259
  type: "host.snapshot",
@@ -249,7 +263,8 @@ async function sendSnapshot(emit) {
249
263
  emit({ type: "host.focus", focus: lastFocus });
250
264
  }
251
265
  async function sendRegion(ref, emit) {
252
- const { snapshotRegion, resolveRef } = await import('./snapshot-QBV7DTJP.js');
266
+ if (!pageContextOn) return;
267
+ const { snapshotRegion, resolveRef } = await loadSnapshotModule();
253
268
  const el = resolveRef(ref);
254
269
  if (!el) {
255
270
  emit({
@@ -270,55 +285,73 @@ async function callTool(call, emit) {
270
285
  error: "Host tools are read-only in this version; no action was taken."
271
286
  });
272
287
  }
273
- function beginAuth(config, emit) {
274
- const w = window.open(
275
- `${config.origin}/embed/authorize?k=${encodeURIComponent(
276
- config.publishableKey
277
- )}&o=${encodeURIComponent(location.origin)}`,
278
- "mf_auth",
279
- "width=460,height=640"
280
- );
281
- if (!w) return;
282
- const onMsg = (event) => {
283
- if (event.origin !== config.origin) return;
284
- const d = event.data;
285
- if (d?.type !== "mf:embed:auth") return;
286
- window.removeEventListener("message", onMsg);
287
- emit({ type: "host.auth", token: d.token, expiresAt: d.expiresAt });
288
- };
289
- window.addEventListener("message", onMsg);
288
+ function stop() {
289
+ document.removeEventListener("click", onClick, { capture: true });
290
+ document.removeEventListener("submit", onSubmit, { capture: true });
291
+ document.removeEventListener("change", onChange, { capture: true });
292
+ document.removeEventListener("selectionchange", scheduleFocus);
293
+ document.removeEventListener("focusin", scheduleFocus, { capture: true });
294
+ window.removeEventListener("scroll", scheduleFocus, { capture: true });
295
+ if (navFire) {
296
+ window.removeEventListener("popstate", navFire);
297
+ navFire = null;
298
+ }
299
+ if (origPushState) {
300
+ history.pushState = origPushState;
301
+ origPushState = null;
302
+ }
303
+ if (origReplaceState) {
304
+ history.replaceState = origReplaceState;
305
+ origReplaceState = null;
306
+ }
307
+ if (focusTimer) {
308
+ clearTimeout(focusTimer);
309
+ focusTimer = null;
310
+ }
311
+ send = null;
312
+ activity.length = 0;
313
+ lastFocus = {};
314
+ widgetOrigin = "";
315
+ snapshotModule?.clearRefs();
290
316
  }
291
- function start(emit, origin) {
317
+ function start(emit, origin, pageContext = true) {
318
+ stop();
292
319
  send = emit;
293
320
  widgetOrigin = origin || "";
294
321
  lastUrl = location.pathname;
295
- publishContext();
296
- publishArtifactGrants();
297
- watchNavigation();
298
- document.addEventListener("click", onClick, { capture: true, passive: true });
299
- document.addEventListener("submit", onSubmit, {
300
- capture: true,
301
- passive: true
302
- });
303
- document.addEventListener("change", onChange, {
304
- capture: true,
305
- passive: true
306
- });
307
- document.addEventListener("selectionchange", scheduleFocus, {
308
- passive: true
309
- });
310
- document.addEventListener("focusin", scheduleFocus, {
311
- capture: true,
312
- passive: true
313
- });
314
- window.addEventListener("scroll", scheduleFocus, {
315
- capture: true,
316
- passive: true
317
- });
322
+ pageContextOn = pageContext;
323
+ if (pageContextOn) {
324
+ publishContext();
325
+ publishArtifactGrants();
326
+ watchNavigation();
327
+ document.addEventListener("click", onClick, {
328
+ capture: true,
329
+ passive: true
330
+ });
331
+ document.addEventListener("submit", onSubmit, {
332
+ capture: true,
333
+ passive: true
334
+ });
335
+ document.addEventListener("change", onChange, {
336
+ capture: true,
337
+ passive: true
338
+ });
339
+ document.addEventListener("selectionchange", scheduleFocus, {
340
+ passive: true
341
+ });
342
+ document.addEventListener("focusin", scheduleFocus, {
343
+ capture: true,
344
+ passive: true
345
+ });
346
+ window.addEventListener("scroll", scheduleFocus, {
347
+ capture: true,
348
+ passive: true
349
+ });
350
+ }
318
351
  const theme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
319
352
  emit({ type: "host.theme", mode: theme });
320
353
  }
321
354
 
322
- export { artifactIdFromPath, beginAuth, callTool, grantsFromIframeSrcs, isPrivate, readPageContext, redact, sendRegion, sendSnapshot, start };
323
- //# sourceMappingURL=chunk-CHPADW72.js.map
324
- //# sourceMappingURL=chunk-CHPADW72.js.map
355
+ export { artifactIdFromPath, callTool, grantsFromIframeSrcs, isPrivate, readPageContext, redact, sendRegion, sendSnapshot, start, stop };
356
+ //# sourceMappingURL=chunk-JSH3BRYP.js.map
357
+ //# sourceMappingURL=chunk-JSH3BRYP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context.ts"],"names":[],"mappings":"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","file":"chunk-JSH3BRYP.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()` installed — remove every\n * listener, restore `history` to what it was before we wrapped it, and forget any\n * DOM-walk module we pulled in. All of this outlives a single `EmbedHost`; see\n * `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/** 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/* ───────────────────────────── stop / start ───────────────────────────── */\n\n/**\n * The opposite number of `start()` — remove every listener it (or `watchNavigation`)\n * installed, restore `history.pushState`/`replaceState` to what they were before we\n * wrapped them, and forget the module-level `send`/`activity`/focus state. Nothing\n * here is a filter over what gets sent afterward — there is simply nothing left\n * 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 (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, {\n capture: true,\n passive: true,\n });\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"]}
@@ -7,6 +7,11 @@ var send = null;
7
7
  var activitySeq = 0;
8
8
  var activity = [];
9
9
  var lastUrl = "";
10
+ var pageContextOn = true;
11
+ var navFire = null;
12
+ var origPushState = null;
13
+ var origReplaceState = null;
14
+ var snapshotModule = null;
10
15
  var PII = [
11
16
  /\b[\w.+-]+@[\w-]+\.[\w.]{2,}\b/g,
12
17
  // email
@@ -193,8 +198,11 @@ function watchNavigation() {
193
198
  publishContext();
194
199
  publishArtifactGrants();
195
200
  };
201
+ navFire = fire;
196
202
  for (const name of ["pushState", "replaceState"]) {
197
203
  const orig = history[name];
204
+ if (name === "pushState") origPushState = orig;
205
+ else origReplaceState = orig;
198
206
  history[name] = function(...args) {
199
207
  const r = orig.apply(this, args);
200
208
  fire();
@@ -216,7 +224,7 @@ async function readFocus() {
216
224
  }
217
225
  const active = document.activeElement;
218
226
  if (active && active !== document.body && !isPrivate(active) && !active.closest("[data-mf-private]")) {
219
- const { snapshot } = await import("./snapshot-IWVXLE4G.js");
227
+ const { snapshot } = await loadSnapshotModule();
220
228
  void snapshot;
221
229
  focus.focused = {
222
230
  label: redact(describeControl(active)),
@@ -231,6 +239,11 @@ async function readFocus() {
231
239
  function describeControl(el) {
232
240
  return describe(el);
233
241
  }
242
+ async function loadSnapshotModule() {
243
+ const m = await import("./snapshot-HYMRZTZC.js");
244
+ snapshotModule = m;
245
+ return m;
246
+ }
234
247
  var focusTimer = null;
235
248
  function scheduleFocus() {
236
249
  if (focusTimer) return;
@@ -242,7 +255,8 @@ function scheduleFocus() {
242
255
  }
243
256
  var snapshotSeq = 0;
244
257
  async function sendSnapshot(emit) {
245
- const { snapshot } = await import("./snapshot-IWVXLE4G.js");
258
+ if (!pageContextOn) return;
259
+ const { snapshot } = await loadSnapshotModule();
246
260
  const { yaml, truncated, visibleRefs } = snapshot();
247
261
  emit({
248
262
  type: "host.snapshot",
@@ -252,7 +266,8 @@ async function sendSnapshot(emit) {
252
266
  emit({ type: "host.focus", focus: lastFocus });
253
267
  }
254
268
  async function sendRegion(ref, emit) {
255
- const { snapshotRegion, resolveRef } = await import("./snapshot-IWVXLE4G.js");
269
+ if (!pageContextOn) return;
270
+ const { snapshotRegion, resolveRef } = await loadSnapshotModule();
256
271
  const el = resolveRef(ref);
257
272
  if (!el) {
258
273
  emit({
@@ -273,51 +288,69 @@ async function callTool(call, emit) {
273
288
  error: "Host tools are read-only in this version; no action was taken."
274
289
  });
275
290
  }
276
- function beginAuth(config, emit) {
277
- const w = window.open(
278
- `${config.origin}/embed/authorize?k=${encodeURIComponent(
279
- config.publishableKey
280
- )}&o=${encodeURIComponent(location.origin)}`,
281
- "mf_auth",
282
- "width=460,height=640"
283
- );
284
- if (!w) return;
285
- const onMsg = (event) => {
286
- if (event.origin !== config.origin) return;
287
- const d = event.data;
288
- if (d?.type !== "mf:embed:auth") return;
289
- window.removeEventListener("message", onMsg);
290
- emit({ type: "host.auth", token: d.token, expiresAt: d.expiresAt });
291
- };
292
- window.addEventListener("message", onMsg);
291
+ function stop() {
292
+ document.removeEventListener("click", onClick, { capture: true });
293
+ document.removeEventListener("submit", onSubmit, { capture: true });
294
+ document.removeEventListener("change", onChange, { capture: true });
295
+ document.removeEventListener("selectionchange", scheduleFocus);
296
+ document.removeEventListener("focusin", scheduleFocus, { capture: true });
297
+ window.removeEventListener("scroll", scheduleFocus, { capture: true });
298
+ if (navFire) {
299
+ window.removeEventListener("popstate", navFire);
300
+ navFire = null;
301
+ }
302
+ if (origPushState) {
303
+ history.pushState = origPushState;
304
+ origPushState = null;
305
+ }
306
+ if (origReplaceState) {
307
+ history.replaceState = origReplaceState;
308
+ origReplaceState = null;
309
+ }
310
+ if (focusTimer) {
311
+ clearTimeout(focusTimer);
312
+ focusTimer = null;
313
+ }
314
+ send = null;
315
+ activity.length = 0;
316
+ lastFocus = {};
317
+ widgetOrigin = "";
318
+ snapshotModule?.clearRefs();
293
319
  }
294
- function start(emit, origin) {
320
+ function start(emit, origin, pageContext = true) {
321
+ stop();
295
322
  send = emit;
296
323
  widgetOrigin = origin || "";
297
324
  lastUrl = location.pathname;
298
- publishContext();
299
- publishArtifactGrants();
300
- watchNavigation();
301
- document.addEventListener("click", onClick, { capture: true, passive: true });
302
- document.addEventListener("submit", onSubmit, {
303
- capture: true,
304
- passive: true
305
- });
306
- document.addEventListener("change", onChange, {
307
- capture: true,
308
- passive: true
309
- });
310
- document.addEventListener("selectionchange", scheduleFocus, {
311
- passive: true
312
- });
313
- document.addEventListener("focusin", scheduleFocus, {
314
- capture: true,
315
- passive: true
316
- });
317
- window.addEventListener("scroll", scheduleFocus, {
318
- capture: true,
319
- passive: true
320
- });
325
+ pageContextOn = pageContext;
326
+ if (pageContextOn) {
327
+ publishContext();
328
+ publishArtifactGrants();
329
+ watchNavigation();
330
+ document.addEventListener("click", onClick, {
331
+ capture: true,
332
+ passive: true
333
+ });
334
+ document.addEventListener("submit", onSubmit, {
335
+ capture: true,
336
+ passive: true
337
+ });
338
+ document.addEventListener("change", onChange, {
339
+ capture: true,
340
+ passive: true
341
+ });
342
+ document.addEventListener("selectionchange", scheduleFocus, {
343
+ passive: true
344
+ });
345
+ document.addEventListener("focusin", scheduleFocus, {
346
+ capture: true,
347
+ passive: true
348
+ });
349
+ window.addEventListener("scroll", scheduleFocus, {
350
+ capture: true,
351
+ passive: true
352
+ });
353
+ }
321
354
  const theme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
322
355
  emit({ type: "host.theme", mode: theme });
323
356
  }
@@ -331,7 +364,7 @@ export {
331
364
  sendSnapshot,
332
365
  sendRegion,
333
366
  callTool,
334
- beginAuth,
367
+ stop,
335
368
  start
336
369
  };
337
- //# sourceMappingURL=chunk-SQJX27LT.js.map
370
+ //# sourceMappingURL=chunk-NZIN3LK7.js.map