Add OpenGraph preview canvas extension#1312
Open
IEvangelist wants to merge 21 commits into
Open
Conversation
Previews OpenGraph metadata as rendered by Facebook, X, LinkedIn, Slack, and Discord. Supports localhost URLs and exposes preview_url and get_metadata canvas actions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Derive chrome surface colors from the guaranteed --text-color-default token via color-mix (with neutral translucent fallbacks) so the URL input, raw-metadata tables, and borders adapt to dark mode instead of using light-only fallback tokens. - Refresh the host panel title whenever a new URL is loaded by re-opening the canvas instance (guarded against reload loops), and update the iframe document.title. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rebuild the chrome on documented app theme tokens with shadcn-style controls (soft radii, ghost/primary buttons, segmented tabs) and a single on-theme accent, so the canvas is indistinguishable from the app in light and dark. - Add an open_og_preview agent tool that opens/focuses the canvas (with an optional URL) so it can be summoned on command. - Add a collapsible page-info footer (final URL, HTTP status, tag count, diagnostics summary) with a remembered open/closed state. - Add an aspire.dev quick-example chip and auto-complete the URL scheme (https://, or http:// for localhost). - Add per-value copy buttons in the raw-metadata view. - Add realistic skeleton loaders that mirror the happy-path layout, with shimmer and View-Transition cross-fades, honoring prefers-reduced-motion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mit links - Add /api/raw route + interactive scrollable code/file hovercard - Rich raw-metadata value formatting (colors, numbers, dates, tokens, pills) - Link Twitter/X handles to x.com and recognized commit SHAs to GitHub - Compact page-info footer (stat strip + conditional canonical line) - Theme-aware brand preview cards (dark variants via body[data-mode]) - Unify hover dismissal (scroll/blur/Escape) and fix stuck loading banner Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new self-contained GitHub Copilot canvas extension under .github/extensions/og-preview/ that runs a local loopback server to fetch a target URL, parse OpenGraph/Twitter metadata, and render multi-platform unfurl previews plus raw metadata/diagnostics in a custom UI.
Changes:
- Introduces a new Copilot canvas extension (
extension.mjs) with actions (preview_url,get_metadata) and a loopback HTTP server providing/api/fetch,/api/img,/api/raw, and/events. - Adds a dependency-free Node HTTP(S) fetcher and regex-based OG/meta parser (
lib/http-fetch.mjs,lib/parse-og.mjs). - Adds a complete UI (HTML/CSS/JS) for previews, raw metadata display, diagnostics, copy helpers, and loading skeletons.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/extensions/og-preview/extension.mjs | Implements the canvas, loopback server routes, SSE push, and agent tools/actions. |
| .github/extensions/og-preview/lib/http-fetch.mjs | Dependency-free HTTP(S) fetch with redirects/timeout/size cap. |
| .github/extensions/og-preview/lib/parse-og.mjs | Parses meta/link/title tags into resolved fields, grouped raw tags, and diagnostics. |
| .github/extensions/og-preview/ui/index.html | UI skeleton for URL input, tabbed sections, and footer. |
| .github/extensions/og-preview/ui/app.js | Client-side rendering, skeleton states, hover previews, copy actions, and SSE handling. |
| .github/extensions/og-preview/ui/styles.css | Styling for canvas chrome and platform-like preview cards. |
| .github/extensions/og-preview/README.md | Documents features, routes, actions/tools, and file layout. |
| .github/extensions/og-preview/copilot-extension.json | Declares the extension name and version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ons, faithful X card
- Make Browse the default first tab; it now drives the previews. In-frame
navigation binds the landed route to the top-level URL (bidirectional).
- Render the browse frame via srcdoc (inline proxied HTML) so it loads inside
the canvas host without "refused to connect"; bridge no longer self-navigates.
- Lay previews out in a multi-column masonry grid to remove wasted vertical space.
- Unify all disclosure chevrons (previews, raw metadata, diagnostics, footer)
to one stroked chevron with a smooth transition; move the preview chevron to
the right of its header.
- Polish collapsible sections: rounded header bounding box, hover state, and a
grid-rows height animation.
- Fix the X/Twitter card to render summary_large_image faithfully — image with a
bottom-left domain pill and no overlapping/floating text; small summary card
used as the no-image fallback.
- Add Bluesky and Microsoft Teams previews with brand icons; prefix the canvas
title with "OG Viewer - {url}".
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…istence
- Run JS inside the Browse iframe safely: inject in-memory localStorage/
sessionStorage/cookie shims so opaque-origin boot code stops throwing, and
harden the sandbox to "allow-scripts allow-forms".
- Unify the Browse route input with the top URL input styling; bump the browse
icon to 15px.
- Fix about:srcdoc navigation: resolve about: URLs' query/hash back onto the real
page URL in the bridge, and ignore non-http nav targets in the parent.
- Add a Previews layout toggle: List (default, larger single column) vs Grid
(compact masonry), persisted to localStorage.
- Persist in-frame client state (e.g. aspire.dev's selected language tab): tag
pushState/replaceState navigations as "soft" so the parent refreshes previews
without reloading the frame, while link clicks ("hard") still re-render it.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ader - Replace malformed grid toggle icon with a clean 2x2 grid octicon - Add a "Link previews" header to the previews toolbar, left of the layout toggle - Add Reddit (compact link card) and Mastodon (vertical status card) previews with brand icons, colors, and light/dark styles Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- http-fetch: reject (not hang) when the response exceeds the size cap; add an SSRF guard that denies private/link-local/unique-local/CGNAT and cloud-metadata (169.254.169.254) ranges by default while always allowing localhost/loopback (opt in to private targets via OG_ALLOW_PRIVATE_NETWORK). - parse-og: resolve a relative <link rel=canonical> href against the base URL. - ARIA tabs: real aria-selected/aria-controls + role=tabpanel/aria-labelledby linkage, roving tabindex, and Arrow/Home/End keyboard navigation. - /api/raw: return a clear error instead of dumping an HTML error/redirect page into the code hovercard (fixes e.g. a .mdx value resolving to a 404 HTML page); guards both HTTP >= 400 and HTML content on a non-html extension. - Browse tab: drop its separate URL bar and drive it from the main address bar; move an "open in browser" button into the main toolbar (shown only on Browse); Reload now force-refreshes the embedded frame on the Browse tab. - Previews: the List layout now flows into multiple columns on wide panels (column-width 480px) while staying single-column on narrow panels. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Swap the jarring "Fetching…" loading banner (which inserted between the header and content and shifted layout) for a thin trickle bar pinned to the bottom edge of the sticky toolbar. It fades in/out with body.is-busy and the fill width animates from JS (10% → cap 90% while loading, snap to 100% on completion). Removes the old spinner keyframes; #status now shows errors only. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The browse iframe is sandboxed without allow-same-origin (opaque origin), so the framed page's ES-module scripts were blocked by CORS and its JS never ran (no theme toggle, sidebar, menus). Route the page's scripts, stylesheets and fonts through /api/proxy with Access-Control-Allow-Origin so the opaque-origin frame can load them — no allow-same-origin, so the page still can't reach the host canvas. Subresources use a path-style proxy URL (/api/proxy/<scheme>/<host>/<path>) so a bundle's relative imports resolve back through the proxy automatically. Rewrites JS root-relative/absolute import specifiers and CSS url()/@import targets; inline <style> and inline <script type=module> are rewritten too. Verified on aspire.dev: modules execute (mermaid renders), theme toggle works (light→dark), and link navigation still posts real URLs. Known limitation: Vite dynamic code-split chunks (root-relative at runtime) aren't proxied, so a few advanced diagram features stay inert. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The code hovercard now detects github.com blob/raw URLs, fetches the corresponding raw.githubusercontent.com content, and renders it with a dependency-free multi-language syntax highlighter (markdown/MDX, markup, JSON, CSS, SQL, YAML/TOML, C-like). Failing diagnostics now include a copyable, ready-to-paste AI fix prompt describing the issue, the page URL, and the expected meta tag. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
auto-merge was automatically disabled
July 1, 2026 12:53
Pull request was converted to draft
Add two action buttons to the footer of each diagnostics "AI fix prompt": "Open in Copilot" (opens a Copilot coding session for the page's source repo, seeded with the prompt) and "Create issue" (files an issue on the repo and assigns Copilot). The extension auto-detects the page's GitHub source repo by scanning the full fetched HTML (edit/blob/tree/commit/raw links), not just OG metadata. When no repo is found, the footer shows a muted note instead of buttons. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- ui/styles.css: give the AI fix prompt footer proper horizontal + vertical inset (padding: 9px 11px) aligned with the prompt body, an accent-tinted top border, and a fixed empty/no-repo note state; restore the .diag-docs selector that a prior edit accidentally clobbered (its declarations were orphaned, so the "Open Graph …" docs link lost its top margin and touched the AI prompt box); align the AI-prompt-header copy button with the snippet copy button (head padding-right 8px -> 6px so both sit 7px from the box's right edge). - extension.mjs: the "Open in Copilot" injected instruction (buildOpenSessionMessage) now explicitly tells the agent that if the detected repo is NOT one of the user's configured projects, it must say so plainly and offer alternatives (use "Create issue", or add the repo as a project) rather than improvising a sandbox session. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ar carets
- ui/app.js: replace the "Open in Copilot" button's device-desktop octicon with
the official GitHub Copilot octicon (copilot-16); the "Create issue" button now
uses the official issue-opened-16 path; remove the now-unused device-desktop
entry from the OCTICONS map. The detected-repo footer slug is now a real link
(span.diag-ai-repo -> a.diag-ai-repo with href, target=_blank, rel=noreferrer).
- ui/styles.css: (1) Scrollbar carets fix — Chromium M121+ (the Copilot App
WebView) ignores all ::-webkit-scrollbar pseudo-elements on any element that
also sets standard scrollbar-width/scrollbar-color, so the existing
::-webkit-scrollbar-button{display:none} was ignored and stepper carets
rendered. Move scrollbar-width/scrollbar-color into an
@supports(-moz-appearance:none) (Firefox-only) block and keep the fully custom
::-webkit-scrollbar rules (all -button variants display:none) for Chromium.
(2) Add link styling for a.diag-ai-repo (hover accent + underline slug,
focus-visible outline).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add a new experimental "Agent readiness" section in the Diagnostics tab that probes emerging AI-agent standards (robots.txt, sitemap, Link headers, llms.txt, Markdown negotiation, AI-bot rules, Content Signals, MCP, A2A, Agent Skills, AI-plugin, DNS-AID, OAuth protected-resource/authorization-server, API Catalog) grouped into 5 categories, with per-check AI fix prompts and repo-detected Open-in-Copilot/Create-issue actions. Backed by a new server route /api/agent-readiness in lib/agent-readiness.mjs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extend the OG diagnostics with ogp.me optional/structured checks: og:locale (optional), and, when og:image is present, og:image:alt (recommended), og:image dimensions = width+height (recommended), og:image:type (optional), and og:image:secure_url (optional). Image sub-checks are only emitted when an og:image exists. Adds matching DIAG_HELP guidance (why/fix/example/docs -> ogp.me#structured) so each new check expands with an AI fix prompt. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the header "Try aspire.dev" chip with a colorized "I'm feeling lucky" button group: the gradient main button previews a random site (showing the current target host as a pill), and a shuffle button (official sync octicon, spin animation) retargets to a different random site without loading. Rotates over a curated list of OG-rich sites (aspire.dev, github.com, microsoft.com, astro.build, grpc.io, docker.com, typescriptlang.org, reddit, vercel, nextjs, MDN, stripe, cloudflare, nasa, nodejs, bsky). The empty-state "Try aspire.dev" chip becomes a larger "I'm feeling lucky" button that loads a fresh random site. Removes the now-unused .examples/.chip CSS and data-example handler. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a self-contained GitHub Copilot OpenGraph preview canvas extension under
.github/extensions/og-preview/.What it does
preview_urlandget_metadata.Implementation
extension.mjspluslib/(HTTP fetch + OG parsing) andui/(HTML/CSS/JS).Examples
Validation
Authored and validated end-to-end in a prior session: previews, raw metadata, diagnostics, and localhost handling all confirmed working. All JS files pass
node --check.