Link Unfurl

@theaiplatform/miniapp-sdk/link-unfurl defines the public link.unfurl contribution and renderer payload. A contribution claims one exact HTTPS hostname and one bounded path template. Create another contribution for each additional URL pattern.

Define and Mount an Unfurl

// tap-miniapp.config.ts
import { defineTapMiniapp } from '@theaiplatform/miniapp-sdk/authoring';
import { commandTargetBuilder } from '@theaiplatform/miniapp-sdk/lifecycle';
import {
  TAP_LINK_UNFURL_PROTOCOL_V1,
  defineLinkUnfurlContribution,
} from '@theaiplatform/miniapp-sdk/link-unfurl';

const pullRequestRenderer = {
  id: 'github-pull-request-renderer',
  kind: 'ui.renderer',
  apiVersion: 1,
  lifecycleScope: 'mount',
  targets: {
    desktop: {
      expose: './ui/github-pull-request',
      runtime: 'webview',
    },
  },
  options: {
    protocol: 'tap-federated-view-v1',
    payloadSchema: null,
    hostActions: [],
    hostResources: [],
  },
} as const;

export const pullRequestUnfurl = defineLinkUnfurlContribution({
  id: 'github-pull-request-unfurl',
  kind: 'link.unfurl',
  apiVersion: 1,
  targets: {
    desktop: { runtime: 'host-declarative' },
  },
  lifecycleScope: 'installation',
  options: {
    protocol: TAP_LINK_UNFURL_PROTOCOL_V1,
    rendererContributionId: 'github-pull-request-renderer',
    match: {
      hostname: 'github.com',
      pathTemplate: '/:owner/:repository/pull/:number',
    },
  },
});

export default defineTapMiniapp({
  versionLabel: '1.0.0',
  presentation: {
    name: 'GitHub pull requests',
    slug: 'github-pull-requests',
    description: 'Render GitHub pull requests in chat.',
  },
  compatibility: { tapHost: '>=2.13.2' },
  targets: {
    desktop: {
      remoteName: 'github_pull_requests_desktop',
      exposes: {
        './ui/github-pull-request': {
          source: './src/github-pull-request.ts',
          runtime: 'webview',
        },
      },
      builder: commandTargetBuilder({
        command: 'pnpm',
        args: ['run', 'build:target'],
      }),
    },
  },
  contributions: [pullRequestRenderer, pullRequestUnfurl],
});
// src/github-pull-request.ts
import type { TapLinkUnfurlRendererModule } from '@theaiplatform/miniapp-sdk/link-unfurl';

const renderer: TapLinkUnfurlRendererModule = {
  mount(root, { payload }) {
    const heading = document.createElement('strong');
    heading.textContent = payload.preview.title ?? payload.preview.canonicalUrl;
    root.append(heading);
    return { unmount: () => root.replaceChildren() };
  },
};

export default renderer;

The host, not the package, creates the payload. It includes the normalized link preview, path captures, and a fixed link target. The renderer must treat every value as display data. The canonical link and removal controls remain host-owned outside the iframe.

Matching and selection

  • Only https links are eligible.
  • hostname is lowercase ASCII without a scheme, port, path, or wildcard.
  • pathTemplate contains 1–16 exact segments. A segment is either a URL-safe literal or a named capture such as :number.
  • If more than one authorized package matches, the host does not choose between them and falls back to its generic preview.
  • Package unfurls require Miniapp SDK 0.16.0 and a TAP host compatible with 2.13.2 or newer. Rebuild inline-renderer packages created with an earlier SDK because their bootstrap lacks the enforced WebRTC boundary.

The host tries an authorized package renderer before its built-in and generic presentation. A missing, ambiguous, invalid, or failed package renderer safely falls back to the existing built-in or generic preview.

Public Export Contract

ExportPurposeInputs and resultLifecycle and errorsWorking example
TAP_LINK_UNFURL_PROTOCOL_V1Names the only host-supported link-unfurl payload protocol.Supplies the exact tap-link-unfurl-v1 protocol literal.A mismatched or unsupported protocol is rejected before the renderer is projected.Define and mount an unfurl
TapLinkUnfurlPreviewKindEnumerates the display-safe link categories supplied by the host.Accepts the closed web-page, image, video, audio, or social-post kind.Type only; unknown preview kinds stay on the existing host fallback.Define and mount an unfurl
TapLinkUnfurlPreviewAuthorDescribes optional display-safe author metadata for one preview.Contains optional name, handle, URL, and avatar URL strings.Every field is immutable display data and grants no fetch or navigation authority.Define and mount an unfurl
TapLinkUnfurlPreviewImageDescribes the optional image metadata selected by the host.Contains a URL plus optional alt text, width, and height.The value is display data; the inline-renderer sandbox retains network isolation.Define and mount an unfurl
TapLinkUnfurlPreviewCarries the host-normalized metadata for the matched source link.Contains source and canonical URLs, provider, kind, and optional display data.The host seals this value and keeps canonical link controls outside package UI.Define and mount an unfurl
TapLinkUnfurlTargetV1Defines the fixed host-owned target available to declared actions.Contains the protocol kind, contribution ID, source URL, and path captures.Renderer-authored targets are never accepted; invalid payload pointers fail closed.Define and mount an unfurl
TapLinkUnfurlPayloadV1Defines the immutable payload delivered to one selected renderer.Contains the protocol, preview, captures, and fixed link target.The payload belongs to one document identity and changes only through remount.Define and mount an unfurl
TapLinkUnfurlContributionV1Defines one exact declarative hostname and path-template claim.Selects the desktop target, a renderer contribution, and one bounded match.Invalid, unavailable, unauthorized, or ambiguous claims fall back to host UI.Define and mount an unfurl
defineLinkUnfurlContributionPreserves literal types while checking a v1 unfurl declaration.Accepts one TapLinkUnfurlContributionV1 value and returns the same value.It adds no runtime behavior; SDK and host validation remain authoritative.Define and mount an unfurl
TapLinkUnfurlRendererModuleSpecializes the shared inline renderer for the fixed unfurl payload.Defines mount with a TapLinkUnfurlPayloadV1 mount context.The host mounts lazily and retains built-in or generic fallback on failure.Define and mount an unfurl