createIndicators
createIndicators<const C extends IndicatorsConfig>(config: C): Indicators<C>
Declare what goes into the path. The result is what every other part of the
library is given: next.config.ts, layouts, pages, the client module, the
proxy.
// lib/indicators.ts
import { createIndicators } from '@fairgarden/indicators'
export const indicators = createIndicators({
locales: ['en', 'fr-CA', 'fr'],
defaultLocale: 'en',
prefs: {
theme: { values: ['light', 'dark'] },
tz: { cookie: 'timezone', values: { EST: 'America/(New_York|Toronto)', PST: 'America/Los_Angeles' } },
},
flags: {
tz: { header: 'x-vercel-ip-timezone', values: { EST: 'America/(New_York|Toronto)' } },
lang: { header: 'accept-language', values: { fr: 'fr.*' }, prerender: false },
beta: { cookie: 'beta', values: ['on'] },
},
exclude: ['oidc'],
})
The config is checked when the module loads, so a mistake fails the build
and not a request. The generic is const, so the types of read,
useIndicators and Link's locale prop are as narrow as what was written:
prefs.theme is 'light' | 'dark' | undefined.
Config
| Field | Default | Meaning |
| --- | --- | --- |
| locales | — | every locale served, as it appears in the path |
| defaultLocale | — | the one served when the path names none; must be listed |
| localePrefix | 'as-needed' | 'always' prefixes the default locale too. See Locales |
| localeCookie | 'locale' | the cookie a chosen locale is remembered in, read by the proxy at the root; false for none |
| prefs | {} | choices the user made, keyed by the name that goes in the path |
| flags | {} | facts about the request, likewise |
| exclude | [] | top-level paths never localized, besides _next, api and .well-known |
A locale is letters and digits with - between subtags: en, fr-CA. Keys
are letters, digits, _ and -, starting with a letter or digit.
Duplicates, a default that is not listed, and a locale that is also excluded
are refused.
An indicator
| Field | Default | Meaning |
| --- | --- | --- |
| values | — | an array of literal values, or a record of name to pattern |
| cookie | the key, for a preference | read from this cookie |
| header | the key, for a flag | read from this header |
| query | — | read from this query parameter |
| prerender | true | include in generateStaticParams |
| maxAge | one year | seconds a cookie written by usePref lives |
Exactly one of cookie, header and query. A value is letters, digits,
_ and -, starting with a letter or digit — nothing a URL would
percent-encode, see Paths.
Literal values match the cookie or header exactly. Patterns are
regular expressions matched against the whole raw value — the same way Next
matches has — so 'fr.*' means starts with fr and 'fr' means is
fr. When several patterns of one indicator would match, the first listed
wins.
The result
Besides what the pages below describe, the object carries the resolved config and a few facts:
| Member | |
| --- | --- |
| config | the config with defaults filled in and indicators sorted by key |
| locales, defaultLocale | as given, typed to the literals |
| isLocale(value) | a type guard for a supported locale |
| locale, prefs, flags | the per-level objects |
Types
Indicators<C>, Locale<C>, Prefs<C>, Flags<C> and Resolved<C>
name the pieces for an app that wants to type its own helpers:
import type { Prefs } from '@fairgarden/indicators'
import type { indicators } from './indicators'
type Theme = Prefs<typeof indicators.config>['theme']