UNPKG

@connectifi/agent-web

Version:

A simple web implementation of a connectifi agent

1 lines 9.32 kB
{"version":3,"sources":["../src/iframe/agent/has-storage-access.ts","../src/iframe/agent/path.ts","../src/iframe/agent/tunnel.ts","../../common/src/directories.ts","../src/common/port.ts","../src/iframe/agent/websocket.ts","../src/iframe/agent/message.ts","../src/iframe/agent/main.ts"],"sourcesContent":["export async function hasStorageAccess() {\n if (!document.requestStorageAccess) {\n return true;\n }\n\n if (await document.hasStorageAccess()) {\n return true;\n }\n\n try {\n const permission = await navigator.permissions.query({\n name: 'storage-access' as PermissionName,\n });\n if (!permission) return false;\n if (permission.state === 'granted') {\n try {\n await document.requestStorageAccess();\n return true;\n } catch (error) {\n return false;\n }\n }\n } catch (err) {\n console.error('failed to check storage access:', err);\n }\n return false;\n}\n","const url =\n typeof window !== 'undefined' ? new URL(window.location.href) : undefined;\nconst paths = url?.pathname.split('/');\n\nexport const appId = paths?.[paths.length - 2];\n","import type { IframeTunnelRequest } from '@/common/interop/iframe';\nimport type { TunnelResponse } from '@/common/interop/tunnel';\n\nimport { appId } from './path';\n\nexport async function tunnel({\n instanceId,\n instanceTitle,\n instanceUrl,\n}: IframeTunnelRequest): Promise<TunnelResponse | undefined> {\n const tunnelUrl = `/api/tunnel/${appId}?title=${encodeURIComponent(\n instanceTitle || '',\n )}&src=${encodeURIComponent(\n instanceUrl || '',\n )}&instanceId=${encodeURIComponent(instanceId || '')}`;\n try {\n const res = await fetch(tunnelUrl);\n return res.json();\n } catch (err) {\n console.error('failed to call tunnel:', err);\n }\n}\n","/**\n * Parameter name for directory identifier.\n * Directories can contain a collection of apps.\n */\nexport const directoryParamName = 'subDirectory';\n\n/**\n * Parameter name for namespace identifier.\n * Namespaces can contain a collection of directories, intents and contexts.\n */\nexport const namespaceParamName = 'directory';\n","export const portTimeoutError = new Error(\n 'timed out waiting for iframe message',\n);\n\nexport function isPortTimeoutError(err: unknown) {\n return portTimeoutError === err;\n}\n\nexport function waitForPortMessage<TMessage extends { topic: string }>(\n port: MessagePort,\n topics: Array<TMessage['topic']>,\n timeoutMs: number = 15000,\n) {\n const topicsSet = new Set(topics);\n return new Promise<TMessage>((res, rej) => {\n const timeout =\n timeoutMs > 0\n ? window.setTimeout(() => {\n port.removeEventListener('message', listener);\n rej(portTimeoutError);\n }, timeoutMs)\n : undefined;\n const listener = (event: MessageEvent) => {\n try {\n const response: TMessage = JSON.parse(event.data);\n if (!topicsSet.has(response.topic)) return;\n res(response);\n clearTimeout(timeout);\n port.removeEventListener('message', listener);\n } catch (err) {\n // ignored\n }\n };\n port.addEventListener('message', listener);\n });\n}\n\nexport function postMessageToPort<TMessage extends { topic: string }>(\n port: MessagePort,\n message?: TMessage,\n) {\n if (!message) return;\n port.postMessage(JSON.stringify(message));\n}\n","import type {\n IframeCloseResponse,\n IframeConnectRequest,\n IframeErrorResponse,\n IframeMessageResponse,\n IframeOpenResponse,\n} from '@/common/interop/iframe';\nimport { directoryParamName, namespaceParamName } from '@/common/directories';\nimport { postMessageToPort } from '../../common/port';\n\nexport function createWebSocket(\n port: MessagePort,\n { directory, namespace, instanceId }: IframeConnectRequest,\n) {\n const path = `/interop/?instanceId=${instanceId}&${directoryParamName}=${directory}&${namespaceParamName}=${namespace}`;\n const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';\n const host = window.location.host;\n const url = `${protocol}${host}${path}`;\n\n const ws = new WebSocket(url);\n ws.onopen = () =>\n postMessageToPort<IframeOpenResponse>(port, { topic: 'open' });\n ws.onmessage = ({ data }) =>\n postMessageToPort<IframeMessageResponse>(port, { topic: 'message', data });\n ws.onerror = () =>\n postMessageToPort<IframeErrorResponse>(port, { topic: 'error' });\n ws.onclose = ({ code }) =>\n postMessageToPort<IframeCloseResponse>(port, {\n topic: 'close',\n code,\n directory,\n namespace,\n instanceId,\n });\n return ws;\n}\n","import type {\n IframeHandshakeResponse,\n IframeHasStorageAccessResponse,\n IframeRequest,\n} from '@/common/interop/iframe';\n\nimport { hasStorageAccess } from './has-storage-access';\nimport { tunnel } from './tunnel';\nimport { createWebSocket } from './websocket';\nimport { postMessageToPort } from '../../common/port';\n\nexport function createHandlePortMessage() {\n let ws: WebSocket | undefined;\n\n return async function handlePortMessage(\n port: MessagePort,\n { data }: MessageEvent,\n ) {\n const request: IframeRequest = JSON.parse(data);\n\n switch (request.topic) {\n case 'connect':\n ws?.close();\n ws = createWebSocket(port, request);\n break;\n case 'send':\n ws?.send(JSON.stringify({ action: 'send', message: request.message }));\n break;\n case 'close':\n ws?.close();\n break;\n case 'has-storage-access':\n postMessageToPort<IframeHasStorageAccessResponse>(port, {\n topic: 'has-storage-access',\n hasStorageAccess: await hasStorageAccess(),\n });\n break;\n case 'tunnel':\n postMessageToPort(port, await tunnel(request));\n break;\n }\n };\n}\n\nconst handlePortMessage = createHandlePortMessage();\nexport function handleWindowMessage({ ports }: MessageEvent) {\n if (!ports.length) return;\n\n window.removeEventListener('message', handleWindowMessage);\n\n const port = ports[0];\n port.addEventListener('message', handlePortMessage.bind(undefined, port));\n port.start();\n\n postMessageToPort<IframeHandshakeResponse>(port, { topic: 'handshake' });\n}\n","import { handleWindowMessage } from './message';\n\nwindow.addEventListener('message', handleWindowMessage);\n"],"mappings":"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","names":["hasStorageAccess","permission","err","url","paths","appId","tunnel","instanceId","instanceTitle","instanceUrl","tunnelUrl","appId","err","directoryParamName","namespaceParamName","portTimeoutError","postMessageToPort","port","message","createWebSocket","port","directory","namespace","instanceId","path","directoryParamName","namespaceParamName","protocol","host","url","ws","postMessageToPort","data","code","createHandlePortMessage","ws","port","data","request","createWebSocket","postMessageToPort","hasStorageAccess","tunnel","handlePortMessage","handleWindowMessage","ports","handleWindowMessage"]}