Color mode

Webmention

Receive Webmentions, verify that the source document really links to the target, store them through a pluggable provider, and render verified mentions near articles. The core plugin contains no Cloudflare, Worker, database, or vendor code and depends only on @riebeckite/core.

日本語

Design

  • WebmentionProvider is the storage/runtime seam: it advertises store / query capabilities and exposes store(mention) and query(query). Credentials, database handles, and runtime bindings stay inside the adapter and never reach plugin options or generated output.
  • MemoryWebmentionProvider is included for tests, local previews, and as a provider contract example. It does not persist across processes/isolates.
  • The plugin declares endpoints: POST {endpoint} receives a Webmention and GET {endpoint} returns the verified-mention feed. Route-framework details never enter this package; the HonoX integration (mountRiebeckiteEndpoints) mounts the contract on the host router.
  • Verification fetches the source through an injectable WebmentionSourceFetcher, checks for an outbound link to the target, and records lightweight citation metadata (title, excerpt, author, publication date, and rel-derived type). The default fetcher blocks loopback and private-network hosts, caps the response size, and times out.

Usage

ts
import { webmention } from "@riebeckite/plugin-webmention";
import { d1Storage } from "@riebeckite/webmention-cloudflare";
 
export default {
  plugins: [
    webmention({ provider: d1Storage(env.WEBMENTION_DB) }),
  ],
};

Without a provider the plugin uses an in-memory provider, which is fine for local previews but loses mentions between processes. Supply a durable adapter (see @riebeckite/webmention-cloudflare) for production.

Endpoints

Method Path Behavior
POST /webmentions (default) Accepts application/x-www-form-urlencoded or application/json with source and target. Returns 202 when accepted, 400 with an error code when rejected, or 503 when storage is unavailable.
GET /webmentions (default) Returns the verified-mention feed as JSON: { version, generatedAt, count, mentions }. Supports ?target=, ?limit=, and ?since=. Returns 501 when the provider cannot query.

Rejection codes: invalid_request, missing_source_or_target, target_not_found, invalid_source, invalid_target, source_unreachable, no_link_found.

Rendering

At onManifestCreated the plugin queries the provider once, groups verified mentions by target, and appends a section to each matching entry's HTML. Core synchronizes that HTML with the content the route renders, using stable hooks:

html
<section class="rr-webmention" data-webmention data-webmention-count="2">
  <h2 class="rr-webmention__heading">Mentions</h2>
  <ul class="rr-webmention__list">
    <li class="rr-webmention__item rr-webmention__item--like"
        data-webmention-type="like">…</li>
  </ul>
</section>

Set render: false to skip build-time injection. Applications that render at request time can call getWebmentionsForEntry({ manifest, config, provider, slug }) and renderWebmentionSection(mentions, options) directly, or consume the JSON feed.

Options

Option Default Description
provider in-memory Storage adapter implementing WebmentionProvider.
endpoint "/webmentions" Receive (POST) and feed (GET) path.
render true Append stored mentions to matching entries at manifest time.
headingText "Mentions" Heading for the rendered section.
limit 20 Maximum mentions rendered per article.
className "rr-webmention" Root CSS class of the rendered section.
allowedTargets [] Extra absolute target URLs accepted beyond published entries.
fetchSource global fetch Source fetcher override (tests, custom runtimes).
timeoutMs 10000 Source fetch timeout.
maxBytes 1000000 Maximum accepted source document size.
userAgent plugin default User-Agent used when verifying.
allowPrivateHosts false Allow fetching private-network sources.
nofollow true Add rel="nofollow ugc" to rendered source links.

Only JSON-safe values ever reach the browser. The plugin registers no client entry and no publicConfig, and provider credentials never enter options.

Diagnostics

addDiagnostics reports provider capability gaps (webmention-render-requires-query, webmention-receive-requires-store). At manifest time, mentions whose target is not a published entry are reported as webmention-unmatched-target.

Exports

  • webmention() / webmentionPlugin()
  • MemoryWebmentionProvider, provider/capability types and errors
  • parseWebmentionSource, findTargetLink, verifyWebmention, createWebmentionSourceFetcher
  • renderWebmentionSection, getWebmentionsForEntry, groupMentionsBySlug, buildFeed
  • resolveWebmentionOptions, validateWebmentionOptions

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/webmention/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Webmention
4 +
5 + Receive Webmentions, verify that the source document really links to the
6 + target, store them through a pluggable provider, and render verified mentions
7 + near articles. The core plugin contains **no Cloudflare, Worker, database, or
8 + vendor code** and depends only on `@riebeckite/core`.
9 +
10 + [日本語](./webmention.md)
11 +
12 + ## Design
13 +
14 + - `WebmentionProvider` is the storage/runtime seam: it advertises
15 + `store` / `query` capabilities and exposes `store(mention)` and
16 + `query(query)`. Credentials, database handles, and runtime bindings stay
17 + inside the adapter and never reach plugin options or generated output.
18 + - `MemoryWebmentionProvider` is included for tests, local previews, and as a
19 + provider contract example. It does not persist across processes/isolates.
20 + - The plugin declares `endpoints`: `POST {endpoint}` receives a Webmention and
21 + `GET {endpoint}` returns the verified-mention feed. Route-framework details
22 + never enter this package; the HonoX integration
23 + (`mountRiebeckiteEndpoints`) mounts the contract on the host router.
24 + - Verification fetches the source through an injectable
25 + `WebmentionSourceFetcher`, checks for an outbound link to the target, and
26 + records lightweight citation metadata (title, excerpt, author, publication
27 + date, and `rel`-derived type). The default fetcher blocks loopback and
28 + private-network hosts, caps the response size, and times out.
29 +
30 + ## Usage
31 +
32 + ```ts
33 + import { webmention } from "@riebeckite/plugin-webmention";
34 + import { d1Storage } from "@riebeckite/webmention-cloudflare";
35 +
36 + export default {
37 + plugins: [
38 + webmention({ provider: d1Storage(env.WEBMENTION_DB) }),
39 + ],
40 + };
41 + ```
42 +
43 + Without a provider the plugin uses an in-memory provider, which is fine for
44 + local previews but loses mentions between processes. Supply a durable adapter
45 + (see [`@riebeckite/webmention-cloudflare`](https://github.com/Rerurate514/riebeckite/blob/main/packages/integrations/webmention-cloudflare/README.md))
46 + for production.
47 +
48 + ## Endpoints
49 +
50 + | Method | Path | Behavior |
51 + | ------ | -------------------------- | -------- |
52 + | `POST` | `/webmentions` (default) | Accepts `application/x-www-form-urlencoded` or `application/json` with `source` and `target`. Returns `202` when accepted, `400` with an `error` code when rejected, or `503` when storage is unavailable. |
53 + | `GET` | `/webmentions` (default) | Returns the verified-mention feed as JSON: `{ version, generatedAt, count, mentions }`. Supports `?target=`, `?limit=`, and `?since=`. Returns `501` when the provider cannot query. |
54 +
55 + Rejection codes: `invalid_request`, `missing_source_or_target`,
56 + `target_not_found`, `invalid_source`, `invalid_target`, `source_unreachable`,
57 + `no_link_found`.
58 +
59 + ## Rendering
60 +
61 + At `onManifestCreated` the plugin queries the provider once, groups verified
62 + mentions by target, and appends a section to each matching entry's HTML. Core
63 + synchronizes that HTML with the content the route renders, using stable hooks:
64 +
65 + ```html
66 + <section class="rr-webmention" data-webmention data-webmention-count="2">
67 + <h2 class="rr-webmention__heading">Mentions</h2>
68 + <ul class="rr-webmention__list">
69 + <li class="rr-webmention__item rr-webmention__item--like"
70 + data-webmention-type="like">…</li>
71 + </ul>
72 + </section>
73 + ```
74 +
75 + Set `render: false` to skip build-time injection. Applications that render at
76 + request time can call `getWebmentionsForEntry({ manifest, config, provider,
77 + slug })` and `renderWebmentionSection(mentions, options)` directly, or consume
78 + the JSON feed.
79 +
80 + ## Options
81 +
82 + | Option | Default | Description |
83 + | ------ | ------- | ----------- |
84 + | `provider` | in-memory | Storage adapter implementing `WebmentionProvider`. |
85 + | `endpoint` | `"/webmentions"` | Receive (POST) and feed (GET) path. |
86 + | `render` | `true` | Append stored mentions to matching entries at manifest time. |
87 + | `headingText` | `"Mentions"` | Heading for the rendered section. |
88 + | `limit` | `20` | Maximum mentions rendered per article. |
89 + | `className` | `"rr-webmention"` | Root CSS class of the rendered section. |
90 + | `allowedTargets` | `[]` | Extra absolute target URLs accepted beyond published entries. |
91 + | `fetchSource` | global `fetch` | Source fetcher override (tests, custom runtimes). |
92 + | `timeoutMs` | `10000` | Source fetch timeout. |
93 + | `maxBytes` | `1000000` | Maximum accepted source document size. |
94 + | `userAgent` | plugin default | `User-Agent` used when verifying. |
95 + | `allowPrivateHosts` | `false` | Allow fetching private-network sources. |
96 + | `nofollow` | `true` | Add `rel="nofollow ugc"` to rendered source links. |
97 +
98 + Only JSON-safe values ever reach the browser. The plugin registers no client
99 + entry and no `publicConfig`, and provider credentials never enter options.
100 +
101 + ## Diagnostics
102 +
103 + `addDiagnostics` reports provider capability gaps
104 + (`webmention-render-requires-query`, `webmention-receive-requires-store`). At
105 + manifest time, mentions whose target is not a published entry are reported as
106 + `webmention-unmatched-target`.
107 +
108 + ## Exports
109 +
110 + - `webmention()` / `webmentionPlugin()`
111 + - `MemoryWebmentionProvider`, provider/capability types and errors
112 + - `parseWebmentionSource`, `findTargetLink`, `verifyWebmention`,
113 + `createWebmentionSourceFetcher`
114 + - `renderWebmentionSection`, `getWebmentionsForEntry`,
115 + `groupMentionsBySlug`, `buildFeed`
116 + - `resolveWebmentionOptions`, `validateWebmentionOptions`
117 +
118 + ## See also
119 +
120 + - [Plugin guide](../reference/plugin-api.en.md)
121 + - [@riebeckite/webmention-cloudflare](https://github.com/Rerurate514/riebeckite/blob/main/packages/integrations/webmention-cloudflare/README.md)
122 +