@epic-web/workshop-app 6.71.2 → 6.71.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/build/client/assets/{_exerciseNumber-DOydVFcz.js → _exerciseNumber-FdJ9Amz3.js} +2 -2
  2. package/build/client/assets/{_exerciseNumber-DOydVFcz.js.map → _exerciseNumber-FdJ9Amz3.js.map} +1 -1
  3. package/build/client/assets/{_exerciseNumber_.finished-OYmKydkm.js → _exerciseNumber_.finished-Z7QZ9wk-.js} +2 -2
  4. package/build/client/assets/{_exerciseNumber_.finished-OYmKydkm.js.map → _exerciseNumber_.finished-Z7QZ9wk-.js.map} +1 -1
  5. package/build/client/assets/{_extra-DAAdPX1Q.js → _extra-UkIdJCI9.js} +2 -2
  6. package/build/client/assets/{_extra-DAAdPX1Q.js.map → _extra-UkIdJCI9.js.map} +1 -1
  7. package/build/client/assets/{_layout-CeuWC4em.js → _layout-DQM0capK.js} +2 -2
  8. package/build/client/assets/{_layout-CeuWC4em.js.map → _layout-DQM0capK.js.map} +1 -1
  9. package/build/client/assets/{diff-CLewaNfR.js → diff-DwJn8fSQ.js} +2 -2
  10. package/build/client/assets/{diff-CLewaNfR.js.map → diff-DwJn8fSQ.js.map} +1 -1
  11. package/build/client/assets/{diff-DrdM1MAZ.js → diff-HIgoC1PO.js} +2 -2
  12. package/build/client/assets/{diff-DrdM1MAZ.js.map → diff-HIgoC1PO.js.map} +1 -1
  13. package/build/client/assets/{entry.client-Dbw2ihVI.js → entry.client-DSlySyW6.js} +4 -4
  14. package/build/client/assets/entry.client-DSlySyW6.js.map +1 -0
  15. package/build/client/assets/{epic-video-BO6oqwle.js → epic-video-DEq93iL_.js} +2 -2
  16. package/build/client/assets/{epic-video-BO6oqwle.js.map → epic-video-DEq93iL_.js.map} +1 -1
  17. package/build/client/assets/{epic-video-Ca_s42j5.js → epic-video-DnXXh6qE.js} +68 -68
  18. package/build/client/assets/{epic-video-Ca_s42j5.js.map → epic-video-DnXXh6qE.js.map} +1 -1
  19. package/build/client/assets/{finished-CqdoWQ9b.js → finished-PFz2gTpr.js} +2 -2
  20. package/build/client/assets/{finished-CqdoWQ9b.js.map → finished-PFz2gTpr.js.map} +1 -1
  21. package/build/client/assets/{index-o922xZRF.js → index-CATk0s1i.js} +2 -2
  22. package/build/client/assets/{index-o922xZRF.js.map → index-CATk0s1i.js.map} +1 -1
  23. package/build/client/assets/{index-BHfJ4hna.js → index-DfT8l3cx.js} +2 -2
  24. package/build/client/assets/{index-BHfJ4hna.js.map → index-DfT8l3cx.js.map} +1 -1
  25. package/build/client/assets/{index-BRVfMMSd.js → index-DkDXAMak.js} +2 -2
  26. package/build/client/assets/{index-BRVfMMSd.js.map → index-DkDXAMak.js.map} +1 -1
  27. package/build/client/assets/{manifest-49708768.js → manifest-31b392f2.js} +1 -1
  28. package/build/client/assets/{mdx-BGwe7vvs.js → mdx-Dun3ONG_.js} +2 -2
  29. package/build/client/assets/{mdx-BGwe7vvs.js.map → mdx-Dun3ONG_.js.map} +1 -1
  30. package/build/client/assets/root-BwuJUAM7.js.map +1 -1
  31. package/build/client/assets/{test-CvHPFyBI.js → test-BU7jE-eU.js} +2 -2
  32. package/build/client/assets/{test-CvHPFyBI.js.map → test-BU7jE-eU.js.map} +1 -1
  33. package/build/client/assets/{tests-DlDV-wXQ.js → tests-1-kVRtTc.js} +2 -2
  34. package/build/client/assets/{tests-DlDV-wXQ.js.map → tests-1-kVRtTc.js.map} +1 -1
  35. package/build/server/index.js +48 -21
  36. package/build/server/index.js.map +1 -1
  37. package/instrument.js +5 -0
  38. package/package.json +3 -3
  39. package/build/client/assets/entry.client-Dbw2ihVI.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{w}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as m}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{E as g,D as h}from"./epic-video-Ca_s42j5.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./misc-W4055b-0.js";import"./tooltip-Tlsyx2YO.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";function l(p,r,i={}){const{schema:s}=i,e=crypto.randomUUID();return new Promise((t,o)=>{if(!window.parent||window.parent===window){console.log("[MCP] No parent frame available. Would have sent message:",{type:p,messageId:e,payload:r}),o(new Error("No parent frame available"));return}window.parent.postMessage({type:p,messageId:e,payload:r},"*");function n(a){if(a.data.type!=="ui-message-response"||a.data.messageId!==e)return;window.removeEventListener("message",n);const{response:d,error:f}=a.data.payload;if(f)return o(f);if(!s)return t(d);const c=s.safeParse(d);return c.success?t(c.data):o(c.error)}window.addEventListener("message",n)})}const D=w(function({loaderData:r}){const i=u.useRef(null);u.useEffect(()=>{r.videoInfos?.finally(()=>{if(window.parent.postMessage({type:"ui-lifecycle-iframe-ready"},"*"),!i.current)return;const e=i.current.clientHeight,t=i.current.clientWidth;window.parent.postMessage({type:"ui-size-change",payload:{height:e,width:t}},"*")})},[r.videoInfos]);async function s(e){const t=e.target;if(!(t instanceof HTMLAnchorElement))return;const o=t.href;if(!o)return;e.preventDefault(),e.stopPropagation();const n=o.startsWith("http")?new URL(o):new URL(o,window.location.origin);n.host===window.location.host&&n.pathname==="/login"&&await l("tool",{toolName:"login",params:{workshopDirectory:ENV.EPICSHOP_CONTEXT_CWD}}),await l("link",{url:n.toString()})}return m.jsx("div",{ref:i,onClickCapture:s,children:m.jsx(g,{epicVideoInfosPromise:r.videoInfos,children:m.jsx(h,{url:r.videoUrl})})})});export{D as default};
2
- //# sourceMappingURL=epic-video-BO6oqwle.js.map
1
+ import{w}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as m}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{E as g,D as h}from"./epic-video-DnXXh6qE.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./misc-W4055b-0.js";import"./tooltip-Tlsyx2YO.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";function l(p,r,i={}){const{schema:s}=i,e=crypto.randomUUID();return new Promise((t,o)=>{if(!window.parent||window.parent===window){console.log("[MCP] No parent frame available. Would have sent message:",{type:p,messageId:e,payload:r}),o(new Error("No parent frame available"));return}window.parent.postMessage({type:p,messageId:e,payload:r},"*");function n(a){if(a.data.type!=="ui-message-response"||a.data.messageId!==e)return;window.removeEventListener("message",n);const{response:d,error:f}=a.data.payload;if(f)return o(f);if(!s)return t(d);const c=s.safeParse(d);return c.success?t(c.data):o(c.error)}window.addEventListener("message",n)})}const D=w(function({loaderData:r}){const i=u.useRef(null);u.useEffect(()=>{r.videoInfos?.finally(()=>{if(window.parent.postMessage({type:"ui-lifecycle-iframe-ready"},"*"),!i.current)return;const e=i.current.clientHeight,t=i.current.clientWidth;window.parent.postMessage({type:"ui-size-change",payload:{height:e,width:t}},"*")})},[r.videoInfos]);async function s(e){const t=e.target;if(!(t instanceof HTMLAnchorElement))return;const o=t.href;if(!o)return;e.preventDefault(),e.stopPropagation();const n=o.startsWith("http")?new URL(o):new URL(o,window.location.origin);n.host===window.location.host&&n.pathname==="/login"&&await l("tool",{toolName:"login",params:{workshopDirectory:ENV.EPICSHOP_CONTEXT_CWD}}),await l("link",{url:n.toString()})}return m.jsx("div",{ref:i,onClickCapture:s,children:m.jsx(g,{epicVideoInfosPromise:r.videoInfos,children:m.jsx(h,{url:r.videoUrl})})})});export{D as default};
2
+ //# sourceMappingURL=epic-video-DEq93iL_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"epic-video-BO6oqwle.js","sources":["../../../app/routes/mcp-ui+/__utils.ts","../../../app/routes/mcp-ui+/epic-video.tsx"],"sourcesContent":["import { useEffect } from 'react'\nimport { type z } from 'zod'\n\nexport function useMcpUiInit(rootRef: React.RefObject<HTMLDivElement | null>) {\n\tuseEffect(() => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\tif (!rootRef.current) return\n\n\t\tconst height = rootRef.current.clientHeight\n\t\tconst width = rootRef.current.clientWidth\n\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t'*',\n\t\t)\n\t}, [rootRef])\n}\n\ntype MessageOptions = { schema?: z.ZodSchema }\n\ntype McpMessageReturnType<Options> = Promise<\n\tOptions extends { schema: z.ZodSchema } ? z.infer<Options['schema']> : unknown\n>\n\ntype McpMessageTypes = {\n\ttool: { toolName: string; params: Record<string, unknown> }\n\tprompt: { prompt: string }\n\tlink: { url: string }\n}\n\ntype McpMessageType = keyof McpMessageTypes\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'tool',\n\tpayload: McpMessageTypes['tool'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'prompt',\n\tpayload: McpMessageTypes['prompt'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage(\n\ttype: McpMessageType,\n\tpayload: McpMessageTypes[McpMessageType],\n\toptions: MessageOptions = {},\n): McpMessageReturnType<typeof options> {\n\tconst { schema } = options\n\tconst messageId = crypto.randomUUID()\n\n\treturn new Promise((resolve, reject) => {\n\t\tif (!window.parent || window.parent === window) {\n\t\t\tconsole.log(`[MCP] No parent frame available. Would have sent message:`, {\n\t\t\t\ttype,\n\t\t\t\tmessageId,\n\t\t\t\tpayload,\n\t\t\t})\n\t\t\treject(new Error('No parent frame available'))\n\t\t\treturn\n\t\t}\n\n\t\twindow.parent.postMessage({ type, messageId, payload }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data.type !== 'ui-message-response') return\n\t\t\tif (event.data.messageId !== messageId) return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { response, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(response)\n\n\t\t\tconst parseResult = schema.safeParse(response)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n\nexport { sendMcpMessage }\n\nexport function waitForRenderData<RenderData>(\n\tschema: z.ZodSchema<RenderData>,\n): Promise<RenderData> {\n\treturn new Promise((resolve, reject) => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data?.type !== 'ui-lifecycle-iframe-render-data') return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { renderData, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(renderData)\n\n\t\t\tconst parseResult = schema.safeParse(renderData)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { useEffect, useRef } from 'react'\nimport { data } from 'react-router'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\nimport { type Route } from './+types/epic-video.tsx'\nimport { sendMcpMessage } from './__utils.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('epicVideoLoader')\n\tconst videoUrl = new URL(request.url).searchParams.get('url')\n\tinvariantResponse(videoUrl, 'url param is required')\n\tconst videoInfos = getEpicVideoInfos([videoUrl], {\n\t\trequest,\n\t\ttimings,\n\t})\n\treturn data(\n\t\t{ videoInfos, videoUrl },\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport default function EpicVideoEmbedRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst rootRef = useRef<HTMLDivElement>(null)\n\tuseEffect(() => {\n\t\tvoid loaderData.videoInfos?.finally(() => {\n\t\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\t\tif (!rootRef.current) return\n\n\t\t\tconst height = rootRef.current.clientHeight\n\t\t\tconst width = rootRef.current.clientWidth\n\n\t\t\twindow.parent.postMessage(\n\t\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t\t'*',\n\t\t\t)\n\t\t})\n\t}, [loaderData.videoInfos])\n\n\tasync function handleLinksClick(event: React.MouseEvent<HTMLElement>) {\n\t\tconst target = event.target\n\t\tif (!(target instanceof HTMLAnchorElement)) return\n\n\t\tconst href = target.href\n\t\tif (!href) return\n\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\n\t\tconst url = href.startsWith('http')\n\t\t\t? new URL(href)\n\t\t\t: new URL(href, window.location.origin)\n\t\tconst isLocal = url.host === window.location.host\n\n\t\tif (isLocal && url.pathname === '/login') {\n\t\t\tawait sendMcpMessage('tool', {\n\t\t\t\ttoolName: 'login',\n\t\t\t\tparams: { workshopDirectory: ENV.EPICSHOP_CONTEXT_CWD },\n\t\t\t})\n\t\t}\n\n\t\tawait sendMcpMessage('link', { url: url.toString() })\n\t}\n\n\treturn (\n\t\t<div ref={rootRef} onClickCapture={handleLinksClick}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={loaderData.videoInfos}>\n\t\t\t\t<DeferredEpicVideo url={loaderData.videoUrl} />\n\t\t\t</EpicVideoInfoProvider>\n\t\t</div>\n\t)\n}\n"],"names":["sendMcpMessage","type","payload","options","schema","messageId","resolve","reject","handleMessage","event","response","error","parseResult","epicVideo","_UNSAFE_withComponentProps","loaderData","rootRef","useRef","useEffect","videoInfos","finally","window","parent","postMessage","current","height","clientHeight","width","clientWidth","handleLinksClick","target","HTMLAnchorElement","href","preventDefault","stopPropagation","url","startsWith","URL","location","origin","host","pathname","toolName","params","workshopDirectory","ENV","EPICSHOP_CONTEXT_CWD","toString","ref","onClickCapture","children","jsx","EpicVideoInfoProvider","epicVideoInfosPromise","DeferredEpicVideo","videoUrl"],"mappings":"+jBAwDA,SAASA,EACRC,EACAC,EACAC,EAA0B,CAAA,EACa,CACvC,KAAM,CAAE,OAAAC,GAAWD,EACbE,EAAY,OAAO,WAAA,EAEzB,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACvC,GAAI,CAAC,OAAO,QAAU,OAAO,SAAW,OAAQ,CAC/C,QAAQ,IAAI,4DAA6D,CACxE,KAAAN,EACA,UAAAI,EACA,QAAAH,CAAA,CACA,EACDK,EAAO,IAAI,MAAM,2BAA2B,CAAC,EAC7C,MACD,CAEA,OAAO,OAAO,YAAY,CAAE,KAAAN,EAAM,UAAAI,EAAW,QAAAH,CAAA,EAAW,GAAG,EAE3D,SAASM,EAAcC,EAAqB,CAE3C,GADIA,EAAM,KAAK,OAAS,uBACpBA,EAAM,KAAK,YAAcJ,EAAW,OACxC,OAAO,oBAAoB,UAAWG,CAAa,EAEnD,KAAM,CAAE,SAAAE,EAAU,MAAAC,CAAA,EAAUF,EAAM,KAAK,QAEvC,GAAIE,EAAO,OAAOJ,EAAOI,CAAK,EAC9B,GAAI,CAACP,EAAQ,OAAOE,EAAQI,CAAQ,EAEpC,MAAME,EAAcR,EAAO,UAAUM,CAAQ,EAC7C,OAAKE,EAAY,QAEVN,EAAQM,EAAY,IAAI,EAFEL,EAAOK,EAAY,KAAK,CAG1D,CAEA,OAAO,iBAAiB,UAAWJ,CAAa,CACjD,CAAC,CACF,CCjEA,MAAAK,EAAAC,EAAA,SAA4C,CAC3CC,WAAAA,CACD,EAAyB,CACxB,MAAMC,EAAUC,EAAAA,OAAuB,IAAI,EAC3CC,EAAAA,UAAU,IAAM,CACVH,EAAWI,YAAYC,QAAQ,IAAM,CAEzC,GADAC,OAAOC,OAAOC,YAAY,CAAEtB,KAAM,6BAA+B,GAAG,EAChE,CAACe,EAAQQ,QAAS,OAEtB,MAAMC,EAAST,EAAQQ,QAAQE,aACzBC,EAAQX,EAAQQ,QAAQI,YAE9BP,OAAOC,OAAOC,YACb,CAAEtB,KAAM,iBAAkBC,QAAS,CAAEuB,OAAAA,EAAQE,MAAAA,CAAM,GACnD,GACD,CACD,CAAC,CACF,EAAG,CAACZ,EAAWI,UAAU,CAAC,EAE1B,eAAeU,EAAiBpB,EAAsC,CACrE,MAAMqB,EAASrB,EAAMqB,OACrB,GAAI,EAAEA,aAAkBC,mBAAoB,OAE5C,MAAMC,EAAOF,EAAOE,KACpB,GAAI,CAACA,EAAM,OAEXvB,EAAMwB,eAAA,EACNxB,EAAMyB,gBAAA,EAEN,MAAMC,EAAMH,EAAKI,WAAW,MAAM,EAC/B,IAAIC,IAAIL,CAAI,EACZ,IAAIK,IAAIL,EAAMX,OAAOiB,SAASC,MAAM,EACvBJ,EAAIK,OAASnB,OAAOiB,SAASE,MAE9BL,EAAIM,WAAa,UAC/B,MAAMzC,EAAe,OAAQ,CAC5B0C,SAAU,QACVC,OAAQ,CAAEC,kBAAmBC,IAAIC,oBAAqB,CACvD,CAAC,EAGF,MAAM9C,EAAe,OAAQ,CAAEmC,IAAKA,EAAIY,SAAA,CAAW,CAAC,CACrD,CAEA,aACE,MAAA,CAAIC,IAAKhC,EAASiC,eAAgBpB,EAClCqB,SAAAC,EAAAA,IAACC,EAAA,CAAsBC,sBAAuBtC,EAAWI,WACxD+B,SAAAC,EAAAA,IAACG,EAAA,CAAkBnB,IAAKpB,EAAWwC,SAAU,EAC9C,CAAA,CACD,CAEF,CAAA"}
1
+ {"version":3,"file":"epic-video-DEq93iL_.js","sources":["../../../app/routes/mcp-ui+/__utils.ts","../../../app/routes/mcp-ui+/epic-video.tsx"],"sourcesContent":["import { useEffect } from 'react'\nimport { type z } from 'zod'\n\nexport function useMcpUiInit(rootRef: React.RefObject<HTMLDivElement | null>) {\n\tuseEffect(() => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\tif (!rootRef.current) return\n\n\t\tconst height = rootRef.current.clientHeight\n\t\tconst width = rootRef.current.clientWidth\n\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t'*',\n\t\t)\n\t}, [rootRef])\n}\n\ntype MessageOptions = { schema?: z.ZodSchema }\n\ntype McpMessageReturnType<Options> = Promise<\n\tOptions extends { schema: z.ZodSchema } ? z.infer<Options['schema']> : unknown\n>\n\ntype McpMessageTypes = {\n\ttool: { toolName: string; params: Record<string, unknown> }\n\tprompt: { prompt: string }\n\tlink: { url: string }\n}\n\ntype McpMessageType = keyof McpMessageTypes\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'tool',\n\tpayload: McpMessageTypes['tool'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'prompt',\n\tpayload: McpMessageTypes['prompt'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage(\n\ttype: McpMessageType,\n\tpayload: McpMessageTypes[McpMessageType],\n\toptions: MessageOptions = {},\n): McpMessageReturnType<typeof options> {\n\tconst { schema } = options\n\tconst messageId = crypto.randomUUID()\n\n\treturn new Promise((resolve, reject) => {\n\t\tif (!window.parent || window.parent === window) {\n\t\t\tconsole.log(`[MCP] No parent frame available. Would have sent message:`, {\n\t\t\t\ttype,\n\t\t\t\tmessageId,\n\t\t\t\tpayload,\n\t\t\t})\n\t\t\treject(new Error('No parent frame available'))\n\t\t\treturn\n\t\t}\n\n\t\twindow.parent.postMessage({ type, messageId, payload }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data.type !== 'ui-message-response') return\n\t\t\tif (event.data.messageId !== messageId) return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { response, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(response)\n\n\t\t\tconst parseResult = schema.safeParse(response)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n\nexport { sendMcpMessage }\n\nexport function waitForRenderData<RenderData>(\n\tschema: z.ZodSchema<RenderData>,\n): Promise<RenderData> {\n\treturn new Promise((resolve, reject) => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data?.type !== 'ui-lifecycle-iframe-render-data') return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { renderData, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(renderData)\n\n\t\t\tconst parseResult = schema.safeParse(renderData)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { useEffect, useRef } from 'react'\nimport { data } from 'react-router'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\nimport { type Route } from './+types/epic-video.tsx'\nimport { sendMcpMessage } from './__utils.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('epicVideoLoader')\n\tconst videoUrl = new URL(request.url).searchParams.get('url')\n\tinvariantResponse(videoUrl, 'url param is required')\n\tconst videoInfos = getEpicVideoInfos([videoUrl], {\n\t\trequest,\n\t\ttimings,\n\t})\n\treturn data(\n\t\t{ videoInfos, videoUrl },\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport default function EpicVideoEmbedRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst rootRef = useRef<HTMLDivElement>(null)\n\tuseEffect(() => {\n\t\tvoid loaderData.videoInfos?.finally(() => {\n\t\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\t\tif (!rootRef.current) return\n\n\t\t\tconst height = rootRef.current.clientHeight\n\t\t\tconst width = rootRef.current.clientWidth\n\n\t\t\twindow.parent.postMessage(\n\t\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t\t'*',\n\t\t\t)\n\t\t})\n\t}, [loaderData.videoInfos])\n\n\tasync function handleLinksClick(event: React.MouseEvent<HTMLElement>) {\n\t\tconst target = event.target\n\t\tif (!(target instanceof HTMLAnchorElement)) return\n\n\t\tconst href = target.href\n\t\tif (!href) return\n\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\n\t\tconst url = href.startsWith('http')\n\t\t\t? new URL(href)\n\t\t\t: new URL(href, window.location.origin)\n\t\tconst isLocal = url.host === window.location.host\n\n\t\tif (isLocal && url.pathname === '/login') {\n\t\t\tawait sendMcpMessage('tool', {\n\t\t\t\ttoolName: 'login',\n\t\t\t\tparams: { workshopDirectory: ENV.EPICSHOP_CONTEXT_CWD },\n\t\t\t})\n\t\t}\n\n\t\tawait sendMcpMessage('link', { url: url.toString() })\n\t}\n\n\treturn (\n\t\t<div ref={rootRef} onClickCapture={handleLinksClick}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={loaderData.videoInfos}>\n\t\t\t\t<DeferredEpicVideo url={loaderData.videoUrl} />\n\t\t\t</EpicVideoInfoProvider>\n\t\t</div>\n\t)\n}\n"],"names":["sendMcpMessage","type","payload","options","schema","messageId","resolve","reject","handleMessage","event","response","error","parseResult","epicVideo","_UNSAFE_withComponentProps","loaderData","rootRef","useRef","useEffect","videoInfos","finally","window","parent","postMessage","current","height","clientHeight","width","clientWidth","handleLinksClick","target","HTMLAnchorElement","href","preventDefault","stopPropagation","url","startsWith","URL","location","origin","host","pathname","toolName","params","workshopDirectory","ENV","EPICSHOP_CONTEXT_CWD","toString","ref","onClickCapture","children","jsx","EpicVideoInfoProvider","epicVideoInfosPromise","DeferredEpicVideo","videoUrl"],"mappings":"+jBAwDA,SAASA,EACRC,EACAC,EACAC,EAA0B,CAAA,EACa,CACvC,KAAM,CAAE,OAAAC,GAAWD,EACbE,EAAY,OAAO,WAAA,EAEzB,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACvC,GAAI,CAAC,OAAO,QAAU,OAAO,SAAW,OAAQ,CAC/C,QAAQ,IAAI,4DAA6D,CACxE,KAAAN,EACA,UAAAI,EACA,QAAAH,CAAA,CACA,EACDK,EAAO,IAAI,MAAM,2BAA2B,CAAC,EAC7C,MACD,CAEA,OAAO,OAAO,YAAY,CAAE,KAAAN,EAAM,UAAAI,EAAW,QAAAH,CAAA,EAAW,GAAG,EAE3D,SAASM,EAAcC,EAAqB,CAE3C,GADIA,EAAM,KAAK,OAAS,uBACpBA,EAAM,KAAK,YAAcJ,EAAW,OACxC,OAAO,oBAAoB,UAAWG,CAAa,EAEnD,KAAM,CAAE,SAAAE,EAAU,MAAAC,CAAA,EAAUF,EAAM,KAAK,QAEvC,GAAIE,EAAO,OAAOJ,EAAOI,CAAK,EAC9B,GAAI,CAACP,EAAQ,OAAOE,EAAQI,CAAQ,EAEpC,MAAME,EAAcR,EAAO,UAAUM,CAAQ,EAC7C,OAAKE,EAAY,QAEVN,EAAQM,EAAY,IAAI,EAFEL,EAAOK,EAAY,KAAK,CAG1D,CAEA,OAAO,iBAAiB,UAAWJ,CAAa,CACjD,CAAC,CACF,CCjEA,MAAAK,EAAAC,EAAA,SAA4C,CAC3CC,WAAAA,CACD,EAAyB,CACxB,MAAMC,EAAUC,EAAAA,OAAuB,IAAI,EAC3CC,EAAAA,UAAU,IAAM,CACVH,EAAWI,YAAYC,QAAQ,IAAM,CAEzC,GADAC,OAAOC,OAAOC,YAAY,CAAEtB,KAAM,6BAA+B,GAAG,EAChE,CAACe,EAAQQ,QAAS,OAEtB,MAAMC,EAAST,EAAQQ,QAAQE,aACzBC,EAAQX,EAAQQ,QAAQI,YAE9BP,OAAOC,OAAOC,YACb,CAAEtB,KAAM,iBAAkBC,QAAS,CAAEuB,OAAAA,EAAQE,MAAAA,CAAM,GACnD,GACD,CACD,CAAC,CACF,EAAG,CAACZ,EAAWI,UAAU,CAAC,EAE1B,eAAeU,EAAiBpB,EAAsC,CACrE,MAAMqB,EAASrB,EAAMqB,OACrB,GAAI,EAAEA,aAAkBC,mBAAoB,OAE5C,MAAMC,EAAOF,EAAOE,KACpB,GAAI,CAACA,EAAM,OAEXvB,EAAMwB,eAAA,EACNxB,EAAMyB,gBAAA,EAEN,MAAMC,EAAMH,EAAKI,WAAW,MAAM,EAC/B,IAAIC,IAAIL,CAAI,EACZ,IAAIK,IAAIL,EAAMX,OAAOiB,SAASC,MAAM,EACvBJ,EAAIK,OAASnB,OAAOiB,SAASE,MAE9BL,EAAIM,WAAa,UAC/B,MAAMzC,EAAe,OAAQ,CAC5B0C,SAAU,QACVC,OAAQ,CAAEC,kBAAmBC,IAAIC,oBAAqB,CACvD,CAAC,EAGF,MAAM9C,EAAe,OAAQ,CAAEmC,IAAKA,EAAIY,SAAA,CAAW,CAAC,CACrD,CAEA,aACE,MAAA,CAAIC,IAAKhC,EAASiC,eAAgBpB,EAClCqB,SAAAC,EAAAA,IAACC,EAAA,CAAsBC,sBAAuBtC,EAAWI,WACxD+B,SAAAC,EAAAA,IAACG,EAAA,CAAkBnB,IAAKpB,EAAWwC,SAAU,EAC9C,CAAA,CACD,CAEF,CAAA"}