{"id":50089439,"url":"https://github.com/browserbox/hyper-frame","last_synced_at":"2026-05-22T22:07:13.712Z","repository":{"id":338434292,"uuid":"1155033270","full_name":"BrowserBox/hyper-frame","owner":"BrowserBox","description":"Hyper-Frame — an iframe that can frame any website. The \u003chyper-frame\u003e custom element (@browserbox/hyper-frame).","archived":false,"fork":false,"pushed_at":"2026-04-26T08:59:01.000Z","size":124,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-26T09:32:07.856Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://browserbox.github.io/hyper-frame/","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BrowserBox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T03:35:30.000Z","updated_at":"2026-04-26T08:59:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/BrowserBox/hyper-frame","commit_stats":null,"previous_names":["browserbox/browserbox-api","browserbox/hyper-frame"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/BrowserBox/hyper-frame","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrowserBox%2Fhyper-frame","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrowserBox%2Fhyper-frame/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrowserBox%2Fhyper-frame/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrowserBox%2Fhyper-frame/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BrowserBox","download_url":"https://codeload.github.com/BrowserBox/hyper-frame/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrowserBox%2Fhyper-frame/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33372739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-22T21:56:13.512Z","status":"ssl_error","status_checked_at":"2026-05-22T21:56:10.769Z","response_time":265,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-05-22T22:07:12.785Z","updated_at":"2026-05-22T22:07:13.705Z","avatar_url":"https://github.com/BrowserBox.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hyper-Frame\n\n**`\u003chyper-frame\u003e` — an iframe that can frame any website.**\n\nInstall via npm:\n\n```bash\nnpm i --save @browserbox/hyper-frame\n```\n\n```html\n\u003cscript type=\"module\" src=\"https://hyper-frame.art/hyper-frame.js\"\u003e\u003c/script\u003e\n\u003chyper-frame\n  id=\"bbx\"\n  login-link=\"https://example.com:9999/login?token=your_login_link\"\n  embedder-origin=\"https://app.example.com\"\n  ui-visible=\"false\"\n  allow-user-toggle-ui=\"false\"\n  width=\"100%\"\n  height=\"600\"\u003e\n\u003c/hyper-frame\u003e\n```\n\nBefore starting a self-hosted BrowserBox instance set the allowed embedder origins:\n\n```bash\nexport ALLOWED_EMBEDDING_ORIGINS=\"https://your-site.example.com https://other-embedder.example.com\"\nbbx stop\nbbx setup -p 8888\nbbx start\ncat ~/.config/dosaygo/bbpro/login.link\n```\n\n## Quick Start\n\n```js\nconst bbx = document.querySelector('hyper-frame');\nawait bbx.whenReady();\n\nawait bbx.page.navigate('https://example.com');\nconst tabs = await bbx.tabs.list();\nconst firstTab = tabs[0];\nif (firstTab?.id) {\n  await bbx.tabs.activate(firstTab.id);\n}\n\nawait bbx.click('a.my-link');\nawait bbx.waitForSelector('.result');\nconst title = await bbx.evaluate('document.title');\n\nconst screenshot = await bbx.capture.frame({ format: 'jpeg', quality: 80 });\n\nawait bbx.frameCapture(true);\nconst frame = await bbx.getFrame();\n\nawait bbx.cleanSlate('https://example.com');\n```\n\n## Element Attributes\n\n| Attribute | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `login-link` | yes | — | Full BrowserBox login URL with auth token |\n| `width` | no | `\"100%\"` | CSS width (px if bare number) |\n| `height` | no | `\"100%\"` | CSS height (px if bare number) |\n| `embedder-origin` | no | `\"*\"` | Restrict postMessage origin |\n| `request-timeout-ms` | no | `30000` | API call timeout (ms) |\n| `ui-visible` | no | `true` | Show/hide BrowserBox chrome UI |\n| `allow-user-toggle-ui` | no | `true` | Allow user to toggle UI visibility |\n| `interaction-mode` | no | `\"full\"` | Policy preset: `full`, `limited`, `view-only` |\n| `policy` | no | — | Additional local policy restrictions |\n| `chrome` | no | `\"default\"` | Chrome presentation hint: `none`, `minimal`, `default`, `custom` |\n| `augment-root` | no | `\"open\"` | Augment inspectability hint: `open` or `closed` |\n| `capture` | no | `\"snapshot\"` | Capture policy hint: `off`, `snapshot`, `sampled` |\n| `media-permissions` | no | `\"default\"` | Set to `\"none\"` to deny mic/camera/display-capture |\n| `session-unload-warning` | no | `\"default\"` | Set to `\"none\"` to suppress beforeunload warning |\n| `beforeunload-behavior` | no | `\"default\"` | `\"leave\"` to auto-depart, `\"remain\"` to auto-stay |\n| `first-load-cleanse` | no | — | Close all tabs on first session load; if the value is a URL, open that URL after cleansing |\n\n`first-load-cleanse` runs once for each `login-link`. Use a non-empty URL to close existing tabs and open that replacement tab. Use an empty value, such as `first-load-cleanse=\"\"`, to close existing tabs without opening a replacement. The `firstLoadCleanse(url?)` method follows the same rule: a non-empty string opens that URL, and an empty string performs the delete-only cleanse.\n\n## Namespaced API\n\nAccess via the element (`bbx.tabs.list()`) or via `bbx.session` facade.\n\n### `session`\n\n| Property / Method | Returns | Description |\n|-------------------|---------|-------------|\n| `session.id` | `string \\| null` | Routing machine ID |\n| `session.usable` | `boolean` | Whether session is usable |\n| `session.ready` | `boolean` | Whether API handshake completed |\n| `session.transport` | `string` | Transport mode |\n| `session.health()` | `Promise\u003cHealthReport\u003e` | Probe browser and transport |\n| `session.capabilities()` | `Promise\u003cobject\u003e` | Query supported capabilities |\n| `session.disconnect()` | `void` | Tear down the session |\n| `session.refresh()` | `void` | Reload the embedded iframe |\n\n### `tabs`\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `tabs.list()` | `Promise\u003cTab[]\u003e` | List all open tabs |\n| `tabs.getActive()` | `Promise\u003cTab\u003e` | Get the active tab |\n| `tabs.create({ url, active? })` | `Promise\u003cTab\u003e` | Open a new tab |\n| `tabs.activate(tabId)` | `Promise` | Switch to a tab by ID |\n| `tabs.close(tabId)` | `Promise` | Close a tab by ID |\n| `tabs.closeAll()` | `Promise` | Close all tabs |\n\n### `page`\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `page.navigate(url, opts?)` | `Promise\u003cNavResult\u003e` | Navigate the active tab |\n| `page.url()` | `Promise\u003cstring\u003e` | Active tab URL |\n| `page.title()` | `Promise\u003cstring\u003e` | Active tab title |\n| `page.reload()` | `Promise` | Reload the active tab |\n| `page.back()` | `Promise\u003cboolean\u003e` | Navigate back |\n| `page.forward()` | `Promise\u003cboolean\u003e` | Navigate forward |\n| `page.stop()` | `Promise` | Stop loading |\n| `page.text(opts?)` | `Promise\u003cstring\u003e` | Extract page text |\n| `page.metrics()` | `Promise\u003cPageMetrics\u003e` | Viewport/document dimensions |\n\n### `capture`\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `capture.frame(opts?)` | `Promise\u003cstring\u003e` | Full-page screenshot |\n| `capture.viewport(opts?)` | `Promise\u003cstring\u003e` | Viewport screenshot |\n| `capture.enable(enabled?)` | `Promise\u003cboolean\u003e` | Enable/disable frame capture |\n| `capture.next()` | `Promise\u003cFramePacket \\| null\u003e` | Consume latest frame |\n\n## Events\n\n| Event | Detail | Description |\n|-------|--------|-------------|\n| `ready` | `{ type }` | Legacy handshake completed |\n| `api-ready` | `{ methods, policy? }` | Modern API available |\n| `ready-timeout` | `{ timeoutMs, error }` | Handshake timed out |\n| `tab-created` | `{ index, id, url }` | New tab opened |\n| `tab-closed` | `{ index, id }` | Tab closed |\n| `tab-updated` | `{ id, url, title, faviconDataURI }` | Tab metadata updated |\n| `active-tab-changed` | `{ index, id }` | Active tab switched |\n| `did-navigate` | `{ tabId, url }` | Navigation committed |\n| `policy-denied` | `{ url, reason }` | Navigation blocked |\n| `usability-changed` | `{ usable: boolean }` | Usability state changed |\n| `sos` | `{ reasonCode, message, retryUrl }` | Fatal unusable signal |\n| `disconnected` | — | Session ended |\n\n## Errors\n\nAPI failures use stable `BrowserBoxError` codes: `ERR_NOT_READY`, `ERR_POLICY_DENIED`, `ERR_TIMEOUT`, `ERR_TRANSPORT`, `ERR_UNSUPPORTED`, `ERR_INVALID_ARGUMENT`, `ERR_NOT_FOUND`, `ERR_CONFLICT`, `ERR_INTERNAL`.\n\n## License\n\nAGPL-3.0-or-later\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowserbox%2Fhyper-frame","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrowserbox%2Fhyper-frame","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowserbox%2Fhyper-frame/lists"}