{"id":13824411,"url":"https://github.com/evilkiwi/embed","last_synced_at":"2026-03-11T05:01:41.182Z","repository":{"id":50323805,"uuid":"384395829","full_name":"evilkiwi/embed","owner":"evilkiwi","description":"Vue 3 cross-origin iFrame IPC","archived":false,"fork":false,"pushed_at":"2023-11-11T09:11:48.000Z","size":268,"stargazers_count":44,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-18T06:57:48.310Z","etag":null,"topics":["hooks","iframe","ipc","postmessage","vue"],"latest_commit_sha":null,"homepage":"https://evil.kiwi","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evilkiwi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":"evilkiwi"}},"created_at":"2021-07-09T10:00:51.000Z","updated_at":"2025-03-01T18:27:27.000Z","dependencies_parsed_at":"2023-11-11T10:22:56.347Z","dependency_job_id":"204db6ea-589c-4e7f-ad01-273dcc9134cc","html_url":"https://github.com/evilkiwi/embed","commit_stats":{"total_commits":28,"total_committers":3,"mean_commits":9.333333333333334,"dds":0.2857142857142857,"last_synced_commit":"6c47dbb42590c6695a9d2280b69e7046708c6a92"},"previous_names":["casthub/embed"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/evilkiwi/embed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilkiwi%2Fembed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilkiwi%2Fembed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilkiwi%2Fembed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilkiwi%2Fembed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evilkiwi","download_url":"https://codeload.github.com/evilkiwi/embed/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilkiwi%2Fembed/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30372125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hooks","iframe","ipc","postmessage","vue"],"created_at":"2024-08-04T09:01:02.304Z","updated_at":"2026-03-11T05:01:41.158Z","avatar_url":"https://github.com/evilkiwi.png","language":"TypeScript","funding_links":["https://github.com/sponsors/evilkiwi"],"categories":["Packages","TypeScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@evilkiwi/embed\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/@evilkiwi/embed?style=flat-square\" alt=\"NPM\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://discord.gg/3S6AKZ2GR9\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/discord/1000565079789535324?color=7289DA\u0026label=discord\u0026logo=discord\u0026logoColor=FFFFFF\u0026style=flat-square\" alt=\"Discord\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/npm/l/@evilkiwi/embed?style=flat-square\" alt=\"GPL-3.0-only\" /\u003e\n  \u003ch3\u003eEmbedded iFrame IPC for Vue 3\u003c/h3\u003e\n\u003c/div\u003e\n\n`@evilkiwi/embed` provides a single Vue 3 hook which can be used to communicate between an iFrame and its parent via `postMessage` IPC.\n\n- `sync`/`async` messaging/responses\n- Configurable timeouts\n- Bi-directional communication\n- Cross-origin support\n- Same usage/API for both Host \u0026 Client\n- Support for enforcing origins for increased security\n- No limit to number of instances you can use/create at any given time\n- TypeScript\n- Tiny (1.73kb)\n\n## Installation\n\nThis package is available via NPM:\n\n```bash\nyarn add @evilkiwi/embed\n\n# or\n\nnpm install @evilkiwi/embed\n```\n\n## Usage\n\nFor this example, we'll assume the `host` is a webpage (`example.com`) and the `client` is a webpage embedded in an iFrame\n(`frame.example.com`). The only difference between a `host` and a `client` is that the `host` requires an iFrame `ref` for binding and\nsending the messages.\n\n```vue\n/** * Host */\n\u003ctemplate\u003e\n  \u003ciframe src=\"https://frame.example.com\" ref=\"iframe\" sandbox=\"allow-scripts\" /\u003e\n\u003c/template\u003e\n\n\u003cscript lang=\"ts\" setup\u003e\nimport { useEmbed } from '@evilkiwi/embed';\nimport { onMounted, ref } from 'vue';\n\nconst iframe = ref\u003cInstanceType\u003ctypeof HTMLIFrame\u003e\u003e();\n\nconst { send, events } = useEmbed('host', {\n  id: 'shared-id',\n  iframe,\n  remote: 'https://frame.example.com',\n});\n\n// Listen for any synchronous events being emitted over IPC\nevents.on('yay', payload =\u003e {\n  console.log(payload);\n});\n\nonMounted(async () =\u003e {\n  // Send an event to the iFrame and wait for a response.\n  const response = await send('hello-world', {\n    hello: 'world',\n  });\n});\n\u003c/script\u003e\n\n/** * Client */\n\u003ctemplate\u003e\n  \u003cbutton @click.prevent=\"submit\"\u003eClick me!\u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript lang=\"ts\" setup\u003e\nimport { useEmbed } from '@evilkiwi/embed';\n\nconst { handle, post } = useEmbed('client', {\n  id: 'shared-id',\n  remote: 'https://example.com',\n});\n\n// Resolves incoming (a)synchronous operations.\nhandle('hello-world', async payload =\u003e {\n  if (payload.hello === 'world') {\n    return 'hey';\n  }\n\n  return 'go away';\n});\n\nconst submit = () =\u003e {\n  // Send a synchronous event to the host\n  post('yay', { test: 123 });\n};\n\u003c/script\u003e\n```\n\nThis example shows:\n\n- Initializing the Host and Client\n- Sending and waiting for asynchronous events\n- Sending and receiving synchronous events\n\nSince communication is bi-directional, you can use **any of the methods on either Host or Client**. For example, asynchronous operations\naren't limited to Host -\u003e Client, the Client can also call asynchronous operations and the Host can register handlers/resolvers.\n\n| **Option** | **Default**             | **Type**                               | **Description**                                                                           |\n| ---------- | ----------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------- |\n| `id`       | **[Required]**          | `string`                               | The Host and Client that you want to talk to each other should share the \\_same\\_ ID.     |\n| `timeout`  | `15000`                 | `number`                               | Configures the global timeout for all asynchronous operations against this ID pair.       |\n| `iframe`   | **[Required for Host]** | `Ref\u003cInstanceType\u003ctypeof HTMLIFrame\u003e\u003e` | A Vue 3 `ref` for a Template reference.                                                   |\n| `remote`   | `*`                     | `string`                               | A remote URL to limit who can recieve/process Events over this Host/Client pair.          |\n| `debug`    | `false`                 | `boolean`                              | Whether to print Debug messages to the console, providing an overview of the IPC process. |\n\n### Security Note\n\nBy default, if you don't supply a `remote`, the library will process **all** incoming messages and send events that **any** party can\nrecieve. By setting this to a URL (See above example), you can limit this and hugely reduce the impact it has on security.\n\n## To-do\n\n- Add a test suite\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilkiwi%2Fembed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevilkiwi%2Fembed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilkiwi%2Fembed/lists"}