wiki-formant 0.106.0 → 0.107.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -445,6 +445,7 @@ export const generateMetadata = () => ({
445
445
  ```
446
446
 
447
447
  - Next replaces `openGraph` and `twitter` per segment rather than merging, so `pageMetadata` sets both; `sitePageMetadata({ siteName, handle })` binds the fields every page's card needs.
448
+ - `sitePageMetadata({ ..., card: `${SITE_URL}/og` })` binds the site's card route, and a page then passes `card: { title, eyebrow, description, banner }` in place of `image`. `cardUrl(base, fields)` is the same address for JSON-LD: empty fields left out, the order fixed, so one card has one URL.
448
449
  - `articleLd` requires `image`. `collectionLd` is an index over an `ItemList`. `siteGraphLd` is the Organization, WebSite and `WebAPI` `@graph` for the root layout, and `siteRefs(url)` hands out the same `@id`s for a page's `publisher` and `isPartOf`.
449
450
  - `questionPairs(html)` reads a FAQ from headings ending in `?`; `faqPageLd(pairs, url)` is null under two pairs.
450
451
  - `describe(text)` is a meta description from any prose within `DESCRIPTION_LIMIT` (160): whole sentences where they fill half, else cut at a word with an ellipsis.
@@ -209,7 +209,10 @@ export declare function sitePageMetadata(site: {
209
209
  siteName: string;
210
210
  locale?: string;
211
211
  handle?: string;
212
- }): (o: Omit<PageMetadataOptions, "siteName" | "locale" | "handle">) => {
212
+ card?: string;
213
+ }): ({ card, ...o }: Omit<PageMetadataOptions, "siteName" | "locale" | "handle"> & {
214
+ card?: CardFields;
215
+ }) => {
213
216
  openGraph: {
214
217
  publishedTime?: string;
215
218
  modifiedTime?: string;
@@ -243,6 +246,26 @@ export declare function sitePageMetadata(site: {
243
246
  canonical: string;
244
247
  } | undefined;
245
248
  };
249
+ /**
250
+ * What a generated card draws: the text, and a banner that replaces its art.
251
+ * Any other key is a parameter only one site's route reads, such as the palette
252
+ * a radix-wiki section picks.
253
+ */
254
+ export interface CardFields {
255
+ title?: string;
256
+ eyebrow?: string;
257
+ description?: string;
258
+ banner?: string | null;
259
+ [param: string]: string | null | undefined;
260
+ }
261
+ /**
262
+ * The address of a card route drawing `fields`, e.g. `cardUrl(`${SITE_URL}/og`, { title })`.
263
+ * Empty fields are left out, and the order is fixed (title, eyebrow,
264
+ * description, any site key, banner) whatever order the caller wrote, so one
265
+ * card has one URL and the CDN and X cache it once. Three wikis each built this
266
+ * query string by hand; the route that reads it is each site's own.
267
+ */
268
+ export declare function cardUrl(base: string, fields: CardFields): string;
246
269
  /** The `@id` references a page's own node points at for `publisher` and `isPartOf`. */
247
270
  export declare function siteRefs(url: string): {
248
271
  organization: LdNode;
package/dist/metadata.js CHANGED
@@ -257,8 +257,30 @@ export function describe(text, limit = DESCRIPTION_LIMIT) {
257
257
  * locale at all of them.
258
258
  */
259
259
  export function sitePageMetadata(site) {
260
- const bound = { locale: 'en_US', ...site };
261
- return (o) => pageMetadata({ ...o, ...bound });
260
+ const { card: base, ...rest } = site;
261
+ const bound = { locale: 'en_US', ...rest };
262
+ return ({ card, ...o }) => {
263
+ if (card && !base)
264
+ throw new Error('sitePageMetadata: a page passed `card` but the site bound no card route');
265
+ return pageMetadata({ ...o, ...(card ? { image: cardUrl(base, card) } : {}), ...bound });
266
+ };
267
+ }
268
+ const CARD_HEAD = ['title', 'eyebrow', 'description'];
269
+ /**
270
+ * The address of a card route drawing `fields`, e.g. `cardUrl(`${SITE_URL}/og`, { title })`.
271
+ * Empty fields are left out, and the order is fixed (title, eyebrow,
272
+ * description, any site key, banner) whatever order the caller wrote, so one
273
+ * card has one URL and the CDN and X cache it once. Three wikis each built this
274
+ * query string by hand; the route that reads it is each site's own.
275
+ */
276
+ export function cardUrl(base, fields) {
277
+ const keys = [...CARD_HEAD, ...Object.keys(fields).filter(k => !CARD_HEAD.includes(k) && k !== 'banner'), 'banner'];
278
+ const q = new URLSearchParams();
279
+ for (const k of keys)
280
+ if (fields[k])
281
+ q.set(k, fields[k]);
282
+ const query = q.toString();
283
+ return query ? `${base}?${query}` : base;
262
284
  }
263
285
  /** The `@id` references a page's own node points at for `publisher` and `isPartOf`. */
264
286
  export function siteRefs(url) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-formant",
3
- "version": "0.106.0",
3
+ "version": "0.107.0",
4
4
  "description": "The portable half of a wiki: derived taxonomy and facet controls, a version-negotiating MCP transport, markdown twins, block rendering, a rich-text editor engine, conditional-GET plumbing, and the headers and CSP every origin sends.",
5
5
  "type": "module",
6
6
  "license": "MIT",