# Code explanations

Comments such as `// [EXPLAIN-D84]` in this package point to the entry with that code below.

## D: Delivery, preview and the SDK

### [EXPLAIN-D30] WebVTT subtitles in the page's language, for videos

WebVTT subtitles in the page's language, for videos.

### [EXPLAIN-D48] Searches entry names

Searches entry names.

### [EXPLAIN-D73] Generates TypeScript types for a website from the CMS schema endpoint

Generates TypeScript types for a website from the CMS schema endpoint.

### [EXPLAIN-D74] Nested components arrive as nodes ({ id, type, fields, children }), not flattened blocks

Nested components arrive as nodes ({ id, type, fields, children }), not flattened blocks. A slot field holds the node or `null` (Component) or a list of nodes (Components); the delivery API fills it from `children`.

### [EXPLAIN-D75] The API address, https://api.bifrostorbit.com/cms

The API address, https://api.bifrostorbit.com/cms. The SDK finds the delivery API, preview and GraphQL under it.

### [EXPLAIN-D76] A public key (cms_pk_) for published content

A public key (cms_pk_) for published content.

### [EXPLAIN-D77] A secret key (cms_sk_) for drafts

A secret key (cms_sk_) for drafts. Server only: refused in browser code.

### [EXPLAIN-D78] Used when a call names no region

Used when a call names no region.

### [EXPLAIN-D79] Next.js data cache settings for published reads

Next.js data cache settings for published reads. Previews are never cached.

### [EXPLAIN-D80] Per attempt, in milliseconds

Per attempt, in milliseconds. 5 seconds by default.

### [EXPLAIN-D81] Extra attempts after a network error or a 5xx

Extra attempts after a network error or a 5xx. 2 by default.

### [EXPLAIN-D82] Swappable for tests, or to add tracing

Swappable for tests, or to add tracing.

### [EXPLAIN-D83] Status codes whose body still carries an answer, such as resolve's 404 and 410

Status codes whose body still carries an answer, such as resolve's 404 and 410.

### [EXPLAIN-D84] Where the CMS itself is served from, for the preview bridge script

Where the CMS itself is served from, for the preview bridge script.

### [EXPLAIN-D85] Throws CmsNotFoundError when nothing is published at that address

Throws CmsNotFoundError when nothing is published at that address.

### [EXPLAIN-D86] Null instead of throwing, for a route that renders its own 404

Null instead of throwing, for a route that renders its own 404.

### [EXPLAIN-D87] Page, redirect, gone or not found

Page, redirect, gone or not found. Call it before rendering so a moved page redirects instead of a 404.

### [EXPLAIN-D88] Site-wide content such as a footer, by the key an editor gave it

Site-wide content such as a footer, by the key an editor gave it.

### [EXPLAIN-D89] Entries of one content type, for an index

Entries of one content type, for an index. Bodies are left out; fetch the page to render it.

### [EXPLAIN-D90] Every region and language this key may read

Every region and language this key may read.

### [EXPLAIN-D91] The languages of one region, the client's default when none is named, or of every region

The languages of one region, the client's default when none is named, or of every region.

### [EXPLAIN-D92] Popups live now for a page and sign-in state, highest priority first

Popups live now for a page and sign-in state, highest priority first. Show at most one.

### [EXPLAIN-D93] Banners live now for a page, pinned first, with countdowns worked out

Banners live now for a page, pinned first, with countdowns worked out.

### [EXPLAIN-D94] Shop products for a region, with live prices

Shop products for a region, with live prices. `filter` is a shop filter's value, such as antioxidant.

### [EXPLAIN-D95] Pass the expected shape as `T`

Pass the expected shape as `T`. Errors in the answer are thrown, not returned beside partial data.

### [EXPLAIN-D96] Content types and components, for generating types

Content types and components, for generating types.

### [EXPLAIN-D97] The key was missing, wrong, revoked, expired, or not allowed to read drafts

The key was missing, wrong, revoked, expired, or not allowed to read drafts.

### [EXPLAIN-D98] Nothing is published at that address in that region and language

Nothing is published at that address in that region and language.

### [EXPLAIN-D99] Too many requests for this key or address

Too many requests for this key or address. Try again after `retryAfter` seconds.

### [EXPLAIN-D100] The CMS could not be reached, timed out, or failed

The CMS could not be reached, timed out, or failed. A cached page should be served instead.

### [EXPLAIN-D101] For a page that was live and has been taken down

For a page that was live and has been taken down. Next.js cannot answer 410 from a page, so this
renders the not-found page; send a true 410 from `proxy.ts` where that matters.

### [EXPLAIN-D102] The website's preview route

The website's preview route. Checks the CMS preview token, turns on draft mode and sends the
editor to the page. Accepts `?token=` or `?preview=`, and an optional `?path=` on this site.

### [EXPLAIN-D103] Only ever a path on this site, so the link cannot be used to send someone elsewhere

Only ever a path on this site, so the link cannot be used to send someone elsewhere.

### [EXPLAIN-D104] Leaves preview

Leaves preview: turns draft mode off and goes back to the page.

### [EXPLAIN-D105] Popups and banners have no address, so any change to an entry without one refreshes them

Popups and banners have no address, so any change to an entry without one refreshes them.

### [EXPLAIN-D106] The website's webhook receiver

The website's webhook receiver. Verifies the CMS signature, refuses anything older than five
minutes, and refreshes only the pages, menus and sitemaps the event touched.

### [EXPLAIN-D107] A region's sitemap, for `app/[region]/sitemap.xml/route.ts`

A region's sitemap, for `app/[region]/sitemap.xml/route.ts`. Large regions continue in
`sitemap-2.xml` and so on, from the same handler at `app/[region]/[file]/route.ts` if needed.

### [EXPLAIN-D108] The sitemap index across every region, for `app/sitemap.xml/route.ts`

The sitemap index across every region, for `app/sitemap.xml/route.ts`.

### [EXPLAIN-D109] robots.txt as the SEO Manager set it in the CMS

robots.txt as the SEO Manager set it in the CMS. Staging always blocks crawlers.

### [EXPLAIN-D110] Loads the CMS bridge script while previewing only, so editors can select blocks in the…

Loads the CMS bridge script while previewing only, so editors can select blocks in the live preview.

### [EXPLAIN-D111] Renders a page's components through the website's own components; the CMS never ships…

Renders a page's components through the website's own components; the CMS never ships markup.

### [EXPLAIN-D112] Shown when the page has no components at all

Shown when the page has no components at all.

### [EXPLAIN-D113] Stable across edits, so it is safe as a React key or an anchor id

Stable across edits, so it is safe as a React key or an anchor id.

### [EXPLAIN-D114] A component's fields with its type, id and variant

A component's fields with its type, id and variant: typed by key once types are generated.

### [EXPLAIN-D115] Nested components, keyed by the slot they were placed in

Nested components, keyed by the slot they were placed in.

### [EXPLAIN-D116] Maps CMS component keys to the website's components

Maps CMS component keys to the website's components. Once types are generated, leaving a
component out is a type error, so a new CMS component cannot reach a page unrendered.

### [EXPLAIN-D117] Visible in development so an authoring mistake is not hidden, silent in production

Visible in development so an authoring mistake is not hidden, silent in production.

### [EXPLAIN-D118] Renders a list of components, such as one held in a field, through the registry

Renders a list of components, such as one held in a field, through the registry.

### [EXPLAIN-D119] Next.js cache tags for CMS reads, so a publish webhook refreshes exactly what changed

Next.js cache tags for CMS reads, so a publish webhook refreshes exactly what changed.

### [EXPLAIN-D120] The reading half of the client, which is what a website's code depends on

The reading half of the client, which is what a website's code depends on.

### [EXPLAIN-D121] Keyed by path, with or without the region prefix

Keyed by path, with or without the region prefix: '/ie/treatments/laser' or '/treatments/laser'.

### [EXPLAIN-D122] Paths that were live and have been taken down

Paths that were live and have been taken down.

### [EXPLAIN-D123] A client that answers from fixtures, for unit tests of website code

A client that answers from fixtures, for unit tests of website code.

### [EXPLAIN-D124] Builders for realistic responses, so tests only state what they care about

Builders for realistic responses, so tests only state what they care about.

### [EXPLAIN-D125] Generated types add each component here, so blocks are typed by their key

Generated types add each component here, so blocks are typed by their key:
`declare module "@orbit/cms-sdk" { interface CmsBlockTypes { hero: HeroBlock } }`

### [EXPLAIN-D126] Where the link goes now; null when it points at a page that is not live

Where the link goes now; null when it points at a page that is not live.

### [EXPLAIN-D127] Rich text as the CMS stores it

Rich text as the CMS stores it: HTML.

### [EXPLAIN-D128] A component nested in a field, typed by its generated block

A component nested in a field, typed by its generated block.

### [EXPLAIN-D129] True when the content came from a fallback language

True when the content came from a fallback language.

### [EXPLAIN-D130] True when the content came from the website's fallback region

True when the content came from the website's fallback region.

### [EXPLAIN-D131] Set on a landing page past its end date that is kept up

Set on a landing page past its end date that is kept up: show the message instead of the offer.

### [EXPLAIN-D132] The same reporting fields, gathered in one place

The same reporting fields, gathered in one place.

### [EXPLAIN-D133] The client's default region when not given

The client's default region when not given.

### [EXPLAIN-D134] The region's default language when not given

The region's default language when not given.

### [EXPLAIN-D135] Read drafts with the preview key

Read drafts with the preview key. Never cached.

### [EXPLAIN-D136] Refuse to fall back to another language or region

Refuse to fall back to another language or region.

### [EXPLAIN-D137] At most 100

At most 100.

### [EXPLAIN-D138] Field key to value

Field key to value.

### [EXPLAIN-D139] What to show now

What to show now. Never an empty bar: "hidden" means show nothing at all.

### [EXPLAIN-D140] One block of a popup or banner, already filtered for guest or signed-in visitors

One block of a popup or banner, already filtered for guest or signed-in visitors.

### [EXPLAIN-D141] In order; render each block by its type

In order; render each block by its type.

### [EXPLAIN-D142] The bar's content in order

The bar's content in order: messages, buttons, promo codes and countdowns.

### [EXPLAIN-D143] The first message, for a website that shows one line

The first message, for a website that shows one line.

### [EXPLAIN-D144] The first button's link

The first button's link.

### [EXPLAIN-D145] The bar's colour, as a hex code such as "#4b2a85"

The bar's colour, as a hex code such as "#4b2a85".

### [EXPLAIN-D146] Text colour that stays readable on the background

The banner's text colour: the one the editor chose, or otherwise white or dark, whichever reads best on the background (see [EXPLAIN-L173]).

### [EXPLAIN-D147] The first countdown

The first countdown.

### [EXPLAIN-D148] The banner that takes over when this one ends, sent ahead with the moment it does, so…

The banner that takes over when this one ends, sent ahead with the moment it does, so the bar can swap at zero
without asking again. Use `useCurrentBanner` to show whichever is due.

### [EXPLAIN-D149] Live items with the CMS's own clock, so a wrong device clock can be corrected

Live items with the CMS's own clock, so a wrong device clock can be corrected.

### [EXPLAIN-D150] The live price from the catalogue; null when it cannot be reached

The live price from the catalogue; null when it cannot be reached.

### [EXPLAIN-D175] An entry delivered in place of its id

What a Reference or References field holds when read with `include: ['references']`: the entry's id, address (or `null`), name, content type, when it was published and its fields. `CmsReference` is the field before you know which way it was read.

### [EXPLAIN-D176] Whether the page was read with references

Set by the client from the request. The live preview asks the CMS for the same expansion, so the components receive values of the same shape while editors type as when the page was first loaded.

### [EXPLAIN-D177] References on pages and globals

Pages, addresses and globals already carry their fields, so `references` is the only extra they take.

### [EXPLAIN-D178] Fields and references on list items

`fields` is only present when the list was read with `include: ['fields']` or `['references']`. Pass the fields' type to `list<F>()` to type it.

### [EXPLAIN-D179] One tag for everything read with references

A page that shows a referenced entry does not know when that entry changes, and a publish webhook names only the entry. Everything read with references carries this tag, and every content change refreshes it, so an edited FAQ entry appears on the pages that show it.

### [EXPLAIN-D180] The page with the editor's latest changes

Only draft pages listen, so published pages never touch the bridge. Content from the editor replaces the page's fields and components and nothing else, so its address, SEO and metadata stay as delivered. It is used only while its address matches the page's, so following a link inside the preview does not show the previous page's content.

### [EXPLAIN-D181] Waiting for the bridge

The bridge script is deferred and may run after the page's components start. It announces itself with a `cms-orbit:ready` event, so the hook subscribes either at once or when that event arrives, and only once. Nothing happens outside the editor.

### [EXPLAIN-D182] A live version of CmsPage

`CmsPage` with `useLivePage` applied. It must be rendered from a client component that imports the registry, because components cannot be passed from the server to the browser.

### [EXPLAIN-D183] Entries for lists in tests

The mock filters them like the API does, by type, field filters, tag, category and name, pages them, and includes fields only when `include` asks for them.

### [EXPLAIN-D184] Types for websites that read references

With `--include references`, Reference and References fields are typed as the entries they point at, narrowed to the allowed content types' fields, to match a website that reads with `include: ['references']`. Without it they stay ids, as before.

### [EXPLAIN-D190] Conditional fields in the schema and generated types

`GET /schema` gives each field's `showWhen`, or `null`, so tools and developers know when a field applies. Generated types make a field with a condition optional even when it is required, since delivery leaves it out while its condition does not hold (see [EXPLAIN-D188]), and add the condition to its comment.

### [EXPLAIN-D191] A webhook expires cached content straight away

Marking the content as stale instead would serve the old copy once more while a fresh one is fetched. For a page that was deleted or taken offline the fresh answer is a 404, which Next.js does not store, so the stale copy was never replaced and the page stayed up. Expiring it means the next visitor waits for the fresh answer, which is what a publish should do anyway, and is what Next.js recommends for webhooks.

### [EXPLAIN-D212] A moved page refreshes the whole site cache

A content webhook normally refreshes only the page's own address and the lists. When it carries a `previousUrl` (see [EXPLAIN-J105]) the page has moved, so cached menus, footers and other pages still link to the old address; the handler refreshes everything instead.

### [EXPLAIN-D213] A published shared section refreshes the whole site cache

A shared section can appear on any page, so its webhook, which carries `contentType: "sharedSection"`, refreshes everything.

### [EXPLAIN-D214] Shared blocks render their blocks in place

Delivery already replaces shared blocks, but the editor's raw preview messages can still contain one, so the renderer draws its `blocks` slot in its place.

## E: Media

### [EXPLAIN-E56] Only images the CMS serves itself can be resized; any other address comes back unchanged

Only images the CMS serves itself can be resized; any other address comes back unchanged.

### [EXPLAIN-E57] Widths for a srcset, none wider than the image itself

Widths for a srcset, none wider than the image itself. Undefined when the image cannot be resized.

### [EXPLAIN-E58] Sets width and height so nothing shifts as it loads

Sets width and height so nothing shifts as it loads. `priority` is for the one image at the top of the page.

### [EXPLAIN-E59] Overrides the alt text written in the CMS

Overrides the alt text written in the CMS.

### [EXPLAIN-E60] Rich text from the CMS, which stores it as HTML

Rich text from the CMS, which stores it as HTML.

### [EXPLAIN-E61] Loads the CMS bridge script, which lets editors select and move blocks inside the live…

Loads the CMS bridge script, which lets editors select and move blocks inside the live preview.
Render it only while previewing; `@orbit/cms-sdk/next` has a version that checks draft mode itself.

## G: SEO, redirects and broken links

### [EXPLAIN-G89] The shape of Next.js `Metadata` that the CMS fills; assignable to it

The shape of Next.js `Metadata` that the CMS fills; assignable to it.

### [EXPLAIN-G90] Title, description, canonical, robots, Open Graph, X card and hreflang for…

Title, description, canonical, robots, Open Graph, X card and hreflang for `generateMetadata`.

### [EXPLAIN-G91] hreflang alternates keyed by language code, x-default included

hreflang alternates keyed by language code, x-default included.

### [EXPLAIN-G92] Closing tags in content must not end the script early

Closing tags in content must not end the script early.

### [EXPLAIN-G93] One region's sitemap file, with hreflang alternates and image entries

One region's sitemap file, with hreflang alternates and image entries.

### [EXPLAIN-G94] A sitemap index pointing at each region's files, at `<base>/sitemap.xml` and…

A sitemap index pointing at each region's files, at `<base>/sitemap.xml` and `<base>/sitemap-<n>.xml`.

## H: Marketing and the shop

### [EXPLAIN-H35] Private browsing may refuse storage; the popup then simply shows again next time

Private browsing may refuse storage; the popup then simply shows again next time.

### [EXPLAIN-H36] The one popup to show on this page view

The one popup to show on this page view: the highest priority that the visitor has not
closed within its hide period or seen too many times. Records the view, and offers dismiss.

### [EXPLAIN-H37] True once it reaches zero on this device, before the next request says what follows

True once it reaches zero on this device, before the next request says what follows.

### [EXPLAIN-H38] Time left on a countdown, ticking every second and corrected by the CMS's clock, so a…

Time left on a countdown, ticking every second and corrected by the CMS's clock, so a device
set to the wrong time still ends the sale at the right moment.

### [EXPLAIN-H39] The banner to show now

The banner to show now: this one until its follow-up's moment, then the follow-up, swapped on the second by the
CMS's clock so a device set to the wrong time still changes over on time.

### [EXPLAIN-H41] Picking the banner for a page in the browser

`bannerFor` does what delivery does for one page: the first banner, already in delivery's order, whose targets match the address, with sections ending in `/*` and every page when it has none. Given a position, it returns that banner only if it asked for that position, so a page shows one banner in one place rather than one above and another under the header. A follow-up that targets other pages is dropped, as delivery would have.

### [EXPLAIN-H44] The website shows the banner as the editor types

In the editor's preview the website listens for the banner being edited and puts it first, replacing its saved copy, so `bannerFor` picks it on the page being previewed and shows it in the position chosen, even before it is scheduled. Outside the editor nothing listens and the banners are unchanged.
