# Registro de cambios (/dev/es/changelog)



# Changelog [#changelog]

All notable changes to the shared UI package `@joeblew999/remy-ui` are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
package follows [Semantic Versioning](https://semver.org/).

## [Unreleased] [#unreleased]

### Changed [#changed]

* GitHub's verdict on a commit is main's push run: a release tag's run on the same commit (the release
  job's) no longer holds `dev:promote` as "still checking".

## \[0.15.1] - 2026-10-11 [#0151---2026-10-11]

### Changed [#changed-1]

* `remy docs publish` is TypeScript in the command line (the three `docs/scripts/*.mjs` are gone) and
  waits for the index's sync it started before asking the fixed questions; `remy docs questions` asks
  them alone. On 2026-10-11 the questions ran seconds after the sync started, against the old index.
* `remy.config.ts` alone sets the origins and the release (`DEPLOY_ORIGIN`, `STAGING_ORIGIN`,
  `DOCS_ORIGIN`, their `VITE_*`, `RELEASE_*`): a value left in the shell by another project is removed,
  where it used to win. The ports still take a value given in the shell.
* GitHub's verdict on a commit (`dev:status`, `dev:change`, `dev:promote`) is its push run's; a
  Dependabot run on the same commit no longer reads as green.
* The check's route tree part also reruns when `src/start.ts` changes (the tree registers the Start
  instance's types).
* `@joeblew999/remy-showcase` 0.1.1 declares what it imports, at the platform's exact versions (a unit
  check holds them equal; `ui:version` keeps them so): in an app whose lock put zod 3 at the top of
  `node_modules`, `zod/mini` resolved to it and the build failed. `@joeblew999/remy-auth-contract` 0.4.1
  (its peer floor).

## \[0.15.0] - 2026-10-11 [#0150---2026-10-11]

0.14.0 was prepared on main and never published; its changes ship here.

### Changed [#changed-2]

* No mise. `package.json` is the entry: its scripts run every command (`npm run dev:status|start|change|land|promote|release|done`, `npm run dev|build|preview|test|setup|packages|docs|…`). The tooling is `remy`, the package's bin (`packages/ui/src/cli`, TypeScript; an app runs the JavaScript emitted from it), with `remy.config.ts` for an app's origins, ports and release package and `.node-version` for Node. The shared workflow runs on `setup-node` and `npm run`; the blank app has no `mise.toml`; an app moves to a release with `npm run upgrade -- <version>`. The deploy's wait ends only when the home page's every asset answers.

## \[0.14.0] - 2026-10-09 [#0140---2026-10-09]

### Added [#added]

* Which version is deployed (remy-sport's build stamp, for every app). `build/vite`: `remyBuild()`, in
  `remyApp()` and `remyDocs()` already, works out a stamp per build from the sources (the app's package,
  the commit, a hash of anything uncommitted, the platform packages' versions) as `virtual:remy-build`.
  Every Worker's `/healthz` answers with it, its `environment` and Cloudflare's `deployedAt`, readable
  from any origin. `versions`: `BuildStamp`, now in the app frame's footer (the environment off
  production, the product's name, the commit, a reload control when the deployment has moved on under
  an open page), and `Versions` (this app, its docs Worker and other listed deployments, each answering
  for itself). `build`: the shapes and TanStack Query options. `mise run cf:versions`: a row per
  deployment, each commit placed against the checkout. Checks in every app's shared set
  (`versions.checks`, `build.checks`).

* Staging: `mise run cf:staging` deploys the Wrangler configuration's `env.staging` (built with
  `CLOUDFLARE_ENV=staging`) to `STAGING_ORIGIN`; `cf:deploy` and its provisioning guard read the
  environment being deployed, and `cf:versions` asks staging too. `defineRemyApp`'s `deployments`:
  the app's deployments, which `Versions` lists. `mail`'s `unreachable(address)`: a message to a
  reserved test or example domain is never sent.

* The product's name is the app's, written once (`defineRemyApp`'s `brand`): `pageTitle`, pageHead's
  `title` and `description` receive it as a second argument, and `productNameChecks` (every app's shared
  set) fails a page of an app with another name that says "Remy". The showcase's Settings page shows
  where the name is used and how another would read (`ProductNameCard`).

* `app-config`: `defineRemyApp` (the app's brand, source, and site and app navigation, each link written
  with TanStack's `linkOptions` so it is checked against the app's own routes), `NavItem`, `useRemyApp`,
  `usePreferredLocale`. The shared frame names no route but `/`, so an app with other pages than
  remy-auth's type-checks and shows only its own.

* `app-shell`: `AppShell` alone, without the showcase pages.

* `@joeblew999/remy-showcase/app-nav`: `showcaseSiteNav`, `showcaseAppNav`, the showcase's lists for apps that show it.

* `docs/*`: the docs Worker itself (Fumadocs on TanStack Start and Cloudflare): `docs/vite`'s
  `remyDocs(docsConfig, { contract })` builds an app's docs from its `docs/content/` and `docs.config.ts`,
  generating the Worker's Cloudflare configuration into `docs/.remy-docs/`; `docs/config`'s
  `defineDocsConfig`; `docs/tsconfig.json` for an app's one-line `docs/tsconfig.json`. Ask AI is opt-in
  (`ask` in `docs.config.ts`); an app without an API (`contract`) has no reference.

* `skills/remy`: the platform's rules as an agent skill, generated from the developer docs; the shared
  `skills:install` installs it, `agents:rules` points `AGENTS.md` at it.

* `defineRemyApp`'s `docs`: the docs Worker's origin; the frame shows the Docs, Developers and Guide links.

* `app/vite`: `remyApp()`, an app's whole `vite.config.ts` (TanStack Devtools, the parts, Cloudflare,
  Fontaine, Tailwind, Start, React), compiling the app's own catalog when it has `project.inlang`.

* `root` (`remyRoot`, `RemyRouterContext`, `preferredLocale`) and `router` (`remyRouter`): an app's
  `__root.tsx` and `router.tsx` are one call each.

* `locale`'s `followLocale(runtime)`: a second Paraglide catalog (an app's or a package's) in the
  platform's language.

* The CSP report route `/csp-report` is the package's, mounted beside every app's routes; `startMiddleware`
  enforces the policy and reports there by default.

* Zod's `jitless` is set once for every app (`AppProviders`) and the docs Worker.

* Tasks: `packages:check`, `packages:upgrade`, `packages:pack`, `packages:release`, `packages:tag`,
  `packages:publish`, `packages:notes` for any repository that publishes packages (its non-private
  workspaces; `RELEASE_PACKAGE`, `RELEASE_TITLE`); `project:release-checks` (a hook), `project:doctor`,
  `project:verify-tooling` (lockfile, `wrangler.jsonc`'s observability and `preview_urls: false`, skill
  pins), `project:single-copies` (in `project:check`), `project:preconditions` (in `project:setup`),
  `project:refresh-tasks`.

* CI: `.github/workflows/google.yml` is a reusable workflow; an app calls it at its tag, and
  `project:upgrade-ui` moves that tag with the package and the tasks.

* `i18n:messages:check` fails when an app's catalog lists other languages than the platform serves.

* `project:test:consumers`: a hook tiers 3 and 4 and CI run last, for the other repositories a repository
  serves (remy-auth: `template:test`, the consumer fixture in `fixtures/consumer/`).

* `packages:publish --dry-run`; `packages:publish` first checks that each registry accepts its token
  (`npm whoami`) and stops on any answer but "not found", before anything is published.

* `template/`: the blank app a new repository starts from (identity, one home page in every language,
  a docs index per site); `docs:init` takes `template/docs`.

* `api/guard-core`: the guard, free of any oRPC import so the same code runs on oRPC 1 and 2: who may call
  a procedure is its `meta.policy` (`public` or `session`), `guardMiddleware` enforces it as the router's
  root middleware, and a procedure that declares none never runs. `guardProblems` names a procedure
  with no policy, with no guard in front of it, a public one whose response names a person (an email
  address, say), and a personal one that does not say who receives it (`meta.personal`).

* `api/guard`: `guard()` (the guard for the installed oRPC, an app router's root middleware),
  `GuardContext` (`getSession`, as oRPC's Better Auth guide shares a session), `once`, `signedIn`,
  `noSession`, and everything in `api/guard-core` and `api/policy`.

* `api/policy`: `policy()` and `personal()`, the oRPC metadata a contract procedure declares for the guard,
  and `actions(vocabulary)` for policies that are actions of the app's relation vocabulary.

* `api/relations`: the relation engine, lifted from remy-sport and taking an app's vocabulary as data
  (`defineVocabulary`, `relationEngine` with `can`, `canAll`, `canFor`, `holds`, `heldAmong`,
  `objectsHeldBy`, `usersHolding`, `audienceFor`; `vocabularyProblems`, `schemaProblems`). The guard
  enforces an action policy with it: 401 without a session, 404 for a missing object before 403.

* `environment`: `environments()`, an app's table of what each environment permits; anything
  undeclared is production. `mail`: `mailerFor`, mail through Cloudflare Email Service or kept in the
  Worker's outbox where the environment captures it.

* `allowed`: `<Allowed can action>`, which shows a control only when the server allowed that action
  for this viewer on this object; `allowed.checks`: `offeredActions`, `allowedActions`.

* `api/server`: `apiHandlers` answers `no-store` to a request with credentials, and on every 401.

* `@joeblew999/remy-showcase/app-pages`: `AccountPage` takes `auth` (who is signed in, and the app's
  sign-in and sign-out controls); without it, the empty state as before.

* `@joeblew999/remy-auth-contract` 0.4.0: `me` (`GET /api/me`, the signed-in person's own account; 401
  without a session), the notes demo (`notes.*`, `notesVocabulary`, `./notes`) and `errorStatuses`;
  written for oRPC 2. `ui:version` sets its peer floor for
  `@joeblew999/remy-ui` to the release.

* Tasks: `project:prepare`, a hook `project:dev` and `project:build` run first (nothing by default);
  `plans:open`, a parked plan taken up again.

### Changed (breaking) [#changed-breaking]

* Every message that named the product takes it as `{product}`: `home_title`,
  `home_description`, `home_intro`, `home_shared_heading`, `home_shared_intro`, `home_developers_text`,
  `formats_description`, `app_home_description`, `account_description`, `account_empty_description`,
  `account_sign_in_description`, `email_code_subject`, `email_code_intro`. Pass
  `{ product: useRemyApp().brand }`; TypeScript names each caller. `showcaseChecks`, `formatsChecks` and
  `preloadChecks` need `product`. Without `AppProviders` the frame's brand is empty, no longer "Remy".
  Three messages nothing used are gone: `ask_description`, `ask_intro`, `search_description`.
* oRPC 2: every `@orpc/*` dependency is 2.0.0-beta.42 (`@orpc/openapi-client` is gone, merged into
  `@orpc/openapi`). An app's contract writes its routes as `.meta(openapi({ method, path, ... }))` and
  its policy as `.meta(policy('public'))` (`api/policy`; `ApiMeta` and `oc.$meta` are gone); its errors
  carry no `status`, and the API's own error codes get theirs from `errorStatuses`, passed to
  `apiHandlers`, `generateSpec`, `apiChecks` and `coverageProblems`. An error's body no longer holds
  `status`. `contractClient(contract, { origin })` replaces `{ url }`. `api/coverage` reads a route
  with `routeOf(procedure)`. A client still on oRPC 1 reads a successful answer but not a typed error.
* `apiChecks` now fails an API whose procedures are not behind the guard. An app with an API puts
  `guard()` (`api/guard`) at its router's root (`implement(contract).$context<GuardContext<...>>().use(guard())`)
  and gives each call a `getSession()` in its context; an app that signs nobody in passes `noSession`.
* Tasks: `cf:deploy` and `cf:preview` refuse when a D1, KV or R2 binding names no existing resource,
  instead of letting Wrangler create one during the deploy.
* One dependency set: the framework, toolchain and the tools the shared tasks run are the package's exact
  dependencies (no more optional peers); an app's `package.json` names `@joeblew999/remy-ui` and drops its
  own pins of them, or `project:single-copies` fails.
* No remy-auth page list is a default: `localizedWorker`'s `entryPaths`, `entryRedirect`, `sitemapXml`'s
  `paths` and `prerenderPages`' `paths` are required; the sitemap lists `defineRemyApp`'s `sitePaths`.
* The shared check sets take the app's `sitePaths` and `appPaths`; the home page's words are checked only
  when the app passes `home`.
* An app's own `src/routes/csp-report.ts`, `src/csp.ts` and `src/preferred.ts` go (the package's route,
  defaults and `root` replace them).
* `defineRemyApp` takes `service` and `sitePaths` (required: the sitemap lists them) and registers the app
  (`registeredApp`); `pageHead`'s titles and the home page's WebSite data use its `brand`, where they used 'Remy'.
* `startMiddleware`'s `csp` is optional. The check sets' `ownSitePaths`, `ownAppPaths`, `formats` and
  `devicePath` options are gone (`sitePaths`, `appPaths`, `showcase`).
* Tests are type-checked: an app's `tsconfig.json` includes `tests/` (the blank app's does). `HomeContent`'s
  functions take a `Locale`.
* remy-auth's showcase pages are a package of their own, `@joeblew999/remy-showcase` (its README): `pages`,
  `app-pages`, `app-nav` (was `showcase/app-nav`), `clock-route`, `reservation`, `search-params`,
  `navigation-blocking`, the showcase's `paths` lists and checks (`showcase.checks`, `reservation.checks`,
  with `reservationApiChecks` from `api/checks`). The platform's `paths` keeps `isAppPath`. The parts' own
  pieces moved into their parts (below); `build-boundaries.checks` and `code-splitting.checks` are at the root; `rows`
  and `zod-csp` are exported.
* Parts from other packages: an app lists another package's part as `<package>/<name>` in `src/parts.json`;
  the package offers them in its `parts/catalog.json`, each part's folder with a `checks.js` whose default
  export runs its checks. The showcase's parts (`time-zones`, `deferred-place`, `status-card`) moved there with their
  pieces (`@joeblew999/remy-showcase/parts/time-zones/page`, `parts/deferred-place/device-place`,
  `parts/status-card/card`, `parts/status-card/query`): list them as `@joeblew999/remy-showcase/<name>`. The time-zones breadcrumb's middle link is the app's `parent`
  option (`src/parts/time-zones.ts`). `problemChecks` lost `timeZones` (the part's own checks now);
  `partChecks` lost `root` and `file`. The platform's own part is `seo-routes`.
* The showcase's checks are one call an app showing the showcase makes itself, `showcaseChecks()`
  (`@joeblew999/remy-showcase/showcase.checks`, with `demoChecks`, `appNavChecks` and `formatsChecks` from
  `checks`); `serverAppChecks` and `prerenderedAppChecks` lost `showcase`. `problem.checks` is at the root.
* `@joeblew999/remy-auth-contract` 0.3.0 imports the reservation from `@joeblew999/remy-showcase` (peer:
  remy-showcase 0.1.0 on); 0.2.1 needs remy-ui below 0.14.
* `packages:bumped` (first in `packages:release`, and in `packages:tag`): a published package whose files
  changed since the last release tag must have a new version, or the release stops.
* `buildBoundaryChecks` checks a page's device time only with `deviceTimePath` (the showcase's `/formats`).
* `project:verify` also runs `project:doctor` and `project:verify-tooling`; `project:generate` compiles
  the app's own catalog by default. A missing `src/parts.json` lists no parts.
* `AppProviders` takes `app` (a `defineRemyApp` config) and `preferred` (the root loader's language) in
  place of `repository`; every frame reads both, so pages no longer pass `preferred`.
* `SourceLink`, `SiteNavLinks` and `AppNavLinks` are gone: the config's `repository`, `site.links` and
  `app.links` replace them.
* `./preferred` (`usePreferred`) is gone: the root passes `preferred` to `AppProviders`.
* `Intro`'s and `FormatsContent`'s `backTo` is `'site' | 'app'` (the app's home comes from the config).
* The sidebar and the phone's bottom bar list the config's `app.nav`, no longer remy-auth's pages; an app
  showing them passes `showcaseAppNav`.
* An app's docs/ is `content/`, `docs.config.ts` and three one-line files (`docs:init` writes them); its
  `wrangler.jsonc`, `src/`, `scripts/`, `tests/` and `playwright.config.ts` go. The shared docs tasks read
  `docs/.remy-docs/wrangler.json`; `docs:publish` and the questions check read `docs/content/questions.json`.
* `mdast-util-to-markdown` is pinned at 2.1.2: 2.1.3 overflows the stack on bold text in Fumadocs' build.

## \[0.13.0] - 2026-09-26 [#0130---2026-09-26]

### Added [#added-1]

* `providers`: `AppProviders`, what an app's root renders its pages in (reading direction, theme, source
  link), so no app misses one (remy-auth-app's theme toggle did nothing without the theme provider).
* `checks`: `themeChecks` (choosing Dark darkens the page), in both app check sets.
* `clock-route`: `clockRouteOptions`, `clockDefaults`, `clockZones` for an app's Clock route.

### Changed [#changed-3]

* `project:check` builds before it type-checks, so a new route's generated route tree is current.

## \[0.12.0] - 2026-09-26 [#0120---2026-09-26]

With `@joeblew999/remy-auth-contract` 0.2.1 (unchanged code; its peer range is now `>=0.12.0`, so a
release changes one version number, not four).

### Added [#added-2]

* Formats page, one shape in every language (issue #5): every section two columns, so none ends with a
  hole; notes in their card's footer (`Group`'s `note`); each language offered its own digits too
  (`ownValues().numberingSystems` adds the numbering systems written in its script: Thai, Devanagari,
  Han, Arabic-Indic), so no language is Latin-only; sorting shows names in every script; `NameList&#x60;
  isolates each name in a mixed-script list. &#x2A;*`FormatsExtras` changed:** `numbers` is rows in the
  Numbers card, `money` is gone and `currencyNote` is the currency card's footer.
* `shell`: `SourceLink`, a context for the site header's "GitHub" link. **An app sets its own
  repository** (`<SourceLink value="https://github.com/you/app">`); without it the header shows no source
  link instead of remy-auth's.
* Translation tasks in two pipelines (`tasks/i18n/`): `i18n:messages:check` and `i18n:docs:check`
  (offline, read-only; git, jq, `@lingual/i18n-check` 0.9.5, a plural-category check), `i18n:check` both
  (a warning; strict with `I18N_STRICT=1`), and `i18n:messages:translate`, `i18n:docs:translate`,
  `i18n:translate`: Claude Code 2.1.282 pinned in the task, with no tools, on main under a lock shared by
  every worktree, committing what it translated. Replaces `i18n:status`, the old `i18n:translate` and the
  provenance lines. Plural messages use `=*` for their fallback variant.
* Mobile navigation (`.plans/done/mobile-navigation.md`): on phones (below `md`, 768 px) a bottom bar
  (`blocks/bottom-nav`, an owned block of stock shadcn parts: shadcn has none) with the core pages and
  More, which opens the sidebar as its sheet; on tablets and desktops the sidebar, now collapsing to
  icons (`collapsible="icon"`). One list feeds both: `app-nav.tsx` (`appNavItems`, `matchesNav`).
* App pages `ClockPage` (time now in chosen zones; the route keeps them), `SettingsPage` (language,
  appearance, the device's zone and languages) and `AccountPage` (an empty state until sign-in);
  `appPaths` gains `/app/clock`, `/app/account`, `/app/settings`, so an app on the package adds those
  three routes when it updates. New catalog keys are English only while translation is frozen.
* `checks`: `appNavChecks` (the phone bar, More, the desktop sidebar, the clock's zones), run by both
  `serverAppChecks` and `prerenderedAppChecks`.
* `checks`: `fontChecks` enforces a font byte budget: a first visit to each site page downloads at
  most `fontBudget` (300 KB, option `budget`) of fonts, in every language. Measured on a local
  production build: 28.7 KB (Latin) to 227.2 KB (`/ar/formats`) (`.plans/fonts.md`, step 1).
  New exports `fontBudget` and `systemFontScripts`.
* Shared tasks `i18n:status`, `i18n:check` and `i18n:translate` (`tasks/i18n/`): per locale, docs
  translations missing or stale against the English version recorded in their first line
  (`<!-- translated-from: <path> @ <blob sha> -->`), and catalog keys missing, extra or with other
  placeholders than the base locale. `project:check` runs `i18n:check` as a warning; `ui:release` runs
  it strict first. An app with nothing to translate gets "nothing to translate". Replaces remy-auth's
  heading-only `docs:translations`.

### Changed [#changed-4]

* `fonts.css`: Japanese and Traditional Chinese draw with the system's font for their language
  (Chrome picks it by the page's `lang`: Hiragino Kaku Gothic ProN and PingFang TC on macOS). Their
  Noto web fonts cost 351 KB (`/ja`) to 1,176 KB (`/zh-TW/formats`) per first visit; now 0 bytes
  beyond Geist. The dependencies `@fontsource-variable/noto-sans-jp` and `-tc` are removed, and the
  build's font files drop from 496 to 25.
* `fonts.css`: Persian draws with Vazirmatn (`@fontsource-variable/vazirmatn` 5.3.0, a
  Persian-designed face; fontsource has no Persian Noto) instead of Noto Sans Arabic: `/fa` downloads
  74 KB of fonts instead of 191 KB, `/fa/formats` 108 KB instead of 259 KB. Arabic keeps Noto Sans Arabic.
* `checks`: `fontChecks` lets a system font draw a Han page, never tofu (LastResort), and its Han
  check compares the fonts that actually draw each language's heading instead of the names in the
  CSS, so Japanese and Traditional Chinese drawn by one font still fails. Every other script still
  needs its web font.

### Changed [#changed-5]

* `checks`: `cspChecks({ enforce })`, default `true`: expects the nonce policy under
  `Content-Security-Policy` (and none under `Content-Security-Policy-Report-Only`), or the reverse
  with `enforce: false`; checks the not-found page's policy too; enforced, proves a script without
  the nonce is blocked and reported. `serverAppChecks({ cspEnforced })` passes the app's switch.
  An app still sending the policy report-only passes `cspEnforced: false`.

## \[0.11.0] - 2026-09-25 [#0110---2026-09-25]

### Added [#added-3]

* Moves that remove copying from consumers (`.plans/publisher-consumer-analysis.md`, D4, D8, D9, D12):
  `./tailwind.css` (`globals.css`, `fonts.css`, `text.css` and the package's own `@source`, so an app
  writes one import and its own `@source "../src"`); `./prerender` (`prerenderPages({ notFoundPath })`,
  a prerendered app's page list); `seo`'s `sitemapXml({ origin, paths, extra })`, `sitemapEntries`,
  `robotsTxt(origin)`, `sitemapType`, `robotsType`; `./app-checks` (`serverAppChecks`,
  `prerenderedAppChecks`: the shared check set in one call per kind of app, the app's own pages
  passed beside the shared ones). remy-auth uses them; its CSS, sitemap, robots.txt and registered
  checks are unchanged. The separate imports keep working.
* `showcase/status-card`: the live status card (`StatusCard`, `LiveStatus`, `statusRefreshMs`), moved
  from remy-auth so remy-auth-app shows it too. The app passes the query: its own client's
  `queryOptions` (server-rendered), or a `contractClient` on another app's origin with
  `serverRendered={false}` (asked by the browser, with its own note, message `live_status_note_browser`).
  An answer that breaks the contract, or none, shows as an error (`data-status="error"`), never as data.
* `./invalidate`: `invalidateEverything(router, queryClient)`, moved from remy-auth (it took the
  router only and read the QueryClient from its context). `@tanstack/react-query` is a new optional peer.
* `api/server`: `apiHandlers` takes `origins`, the registered apps' exact origins allowed to call
  the API from their pages (oRPC's CORSPlugin; none by default, a wildcard is refused).
* `api/checks`: `apiChecks({ origins })` checks CORS: each registered origin allowed on a simple call
  and a preflight, any other origin not.
* `showcase/status-card.checks`: `statusCardChecks({ origin, registered })` for a consumer that asks
  another app's contract across origins (no status in the prerendered HTML, the other Worker names
  the page's origin, nothing asked from an unregistered origin), and for every card on a contract
  endpoint a check that an answer breaking the contract is shown as an error.
* Parts (`.plans/parts.md`): `./parts` (`readParts`, `catalog`), `./parts/vite` (`remyParts()`: a Vite
  plugin generating `virtual:remy-parts` from the app's `src/parts.json`, and the route config that
  mounts each listed part's routes through TanStack's `virtualRouteConfig` and `physical()`),
  `./parts/checks` (`partChecks()`). First part: `time-zones` (the `/time-zones/$` route and its checks),
  so an app adds or removes it with one line. New dependency `@tanstack/virtual-file-routes`.
* Parts, second pass: three more parts, each one line in `src/parts.json`.
  `deferred-place` (Cloudflare's place streamed into the formats and location pages, its `getPlace`
  server function and checks; links a zone to `time-zones` only when that part is listed),
  `seo-routes` (`/robots.txt` and `/sitemap.xml`, listing the package's site pages, every listed part's
  and the app's own entries from its `src/parts/seo-routes.ts`) and `status-card` (the live status card
  on the app home, with the app's status query from its `src/parts/status-card.ts`).
  The mechanism gains entry modules (`virtual:remy-parts/<part>/<entry>`, `undefined` for an unlisted
  part), app options (`virtual:remy-parts/<part>/app`), site paths a part adds (`sitePaths`) and
  `partSitePaths()`. New exports `./parts/seo-routes/sitemap` and `./parts/status-card/query` (types
  for the app's options). One implementation each: the seo-routes part builds its routes with `seo`'s
  `sitemapXml` and `robotsTxt` (as a prerendered app writes its files), and the status-card part is
  `showcase/status-card`'s card with the app's query.
* `serverAppChecks({ parts })` is part-aware: what a listed part owns runs with `partChecks()` instead,
  never twice (with `seo-routes` no sitemap test in `publicPageChecks`; the device-place row expects
  Cloudflare's place only with `deferred-place`). `parts` defaults to the app's `src/parts.json`, or
  none without one; `prerenderedAppChecks` is unchanged. remy-auth's test file is one `serverAppChecks`
  call, one `partChecks` call and its own checks.
* `sitemapChecks({ paths, oneLanguage })` (`checks`): the sitemap test, split out of `publicPageChecks`,
  which runs it unless told `sitemap: false` (the seo-routes part's checks run it then). The 404 check it
  shared a test with is a test of its own, still in `publicPageChecks`.
* `./problem` (`Problem`, `NotFound`, `ErrorPage`, `problemPages`) and `./preferred` (`usePreferred`),
  moved from remy-auth so parts' routes can use them. Nothing changes for existing imports.
* `./smoke`: `smokeChecks({ sitePaths, appPaths, hydrate, locales })`, tier 1 of the test tiers (every page
  answers, site pages with a heading, chosen pages hydrate cleanly) for any app on the package.
* `shell`: the site frame (`SiteShell`, `Shell`, `SiteNavLinks`, `Intro`, `SkipLink`, `ZoneBadge`)
  in a module of its own, so a page that needs only the frame (remy-auth's docs and problem pages)
  no longer downloads the home and formats pages. `pages` re-exports all of it: nothing changes for
  existing imports.
* `publicPageChecks({ oneLanguage: { translations } })`: one-language pages that also have their own
  text in other languages (remy-auth's translated docs) are expected in the sitemap once per language,
  self-canonical, with those languages as alternates and x-default.
* `locale-data` (plain JavaScript, re-exported by `locale-info`): one module that derives, per locale,
  its region, script, currency, calendars, numbering systems and plural counts (`ownValues`), each
  control's choices over all of Paraglide's locales (`allChoices`, `choicesFor`: the page's language's
  own first) and the formats page's `searchDefaults` (from the base locale). The region's currency
  comes from `country-to-currency` (new dependency; the runtime has no currency-for-region API).
* A numbering-system control on the formats page (`?numbering=`), in the Numbers section.
* `LocaleInfo` has `region`, `currency` and `counts`; `Group` passes other props (data attributes) to its card.
* `fontChecks({ paths })` (`checks`): per language, the fonts that actually draw the heading and
  intro (Chrome DevTools Protocol `CSS.getPlatformFontsForNode`) are the ones `fonts.css` names
  for it; a system or fallback font drawing the text fails naming the page's script and the font
  to add, a named script font that draws nothing fails, and Japanese and Traditional Chinese must
  name different fonts.

### Fixed [#fixed]

* `fonts.css`: Arabic, Persian and Hebrew pages are drawn with Noto Sans Arabic and Hebrew on
  macOS and Windows. Each language's script font now comes before fontaine's Geist fallback (local
  Arial, which carries Arabic and Hebrew and so drew them itself), followed by the script font's
  own metric-matched fallback face; Geist's fallback stays last. No new preloads.

### Changed [#changed-6]

* Formats page: every section opens with what it is for the page's language (`data-own-area`):
  Money shows the amount in the language's own currency (was euros), Words lists the language's
  plural forms. Every control offers the union over all locales, the page's own values first, in
  the secondary look and described by a "This language" badge. `currencies`, `countChoices` and the
  showcase calendar list are gone; the currency default is the base locale's (USD, was EUR) and the
  count default its first count above one in the general form (2, was 3).
* `formatsChecks` and `searchParamsChecks` iterate the derived values, so a new locale needs no
  check edit; they also check the "for this language" card of every section and each control's
  order and marking.
* The formats rows (`Group`, `Row`) live in their own module and the showcase modules whose route
  options run in every page's first load (search params, time zones, device place) import them and
  the frame from there instead of from `pages`. `pages` still exports them.

### Added [#added-4]

* `SiteNavLinks` (`pages`): a context through which an app adds its own links to the site header;
  remy-auth adds "Docs". Without it the header is unchanged.
* `publicPageChecks({ oneLanguage })`: site pages written in one language only, listed once in the
  sitemap without alternates and checked on a narrow screen like the others.
* shadcn's `table` component (through `ui:components`), and messages for the docs and the answer
  page in every language.

### Changed [#changed-7]

* `publicPageChecks`: the narrow-screen, fonts and mirrored-header check runs one test per
  language, and one-language pages once, in their own language.

## \[0.10.5] - 2026-09-25 [#0105---2026-09-25]

### Added [#added-5]

* Ten more languages: fa, he, th, ja, zh-TW, hi, am, pl, tr, de (13 in all), each with its Noto
  font from fontsource where Geist has no glyphs, applied by `:lang()`.
* `text.css`: hyphenation by the page's language, casing by `lang` (Turkish İ), phrase breaking for
  Japanese headings. `checks`: `textChecks({ paths })` (every page fits 320 px, per language).
* Formats: each language's own calendar and digits through one explicit format tag
  (`formatTag`), more calendars in the control, week rules from `Intl.Locale` `getWeekInfo`,
  word segmentation with `Intl.Segmenter`, native digits in counts through Paraglide's number
  function.
* `matching.js`: a Paraglide custom strategy that sends Chinese browsers to zh-TW.
* Quick test tier (`project:test:quick`): one language per writing system (`QUICK_LOCALES`,
  default en, ar, ja, th).

### Changed [#changed-8]

* Per-language checks (app pages kept out of search, CSP violations while hydrating, text) run as
  one test per language, so the time per test does not grow with the language count.

## [0.10.4] - 2026-09-25 [#0104---2026-09-25]

### Added [#added-6]

* Site header on shadcn's NavigationMenu (plain links, complete without JavaScript), a footer list of
  every language as real links, and a header language dropdown over the same links whose trigger
  falls back to that list without JavaScript.

* `theme`: shadcn's TanStack Start ThemeProvider and ModeToggle (light, dark, system), on site and
  app pages. Without JavaScript site pages show the default theme.

* Breadcrumb on the time zone pages (shadcn Breadcrumb, server-rendered links).

* `tanstack`: `pageHead` adds schema.org `WebSite` structured data (name, site root) to the site
  home page through TanStack's `script:ld+json` head entry.

* `worker`: every response sends `Content-Security-Policy: frame-ancestors 'none'`,
  `Cross-Origin-Opener-Policy: same-origin-allow-popups` and `Strict-Transport-Security: max-age=300`.

* `checks`: `cspChecks({ paths, reportPath })` for a nonce-based Content Security Policy (nonce on
  every script, no violations while hydrating, report endpoint); `publicPageChecks` and
  `zoneChecks` cover the structured data; `observabilityChecks` covers the new headers.

* `./api/server`, `./api/client`, `./api/coverage`, `./api/checks`: contract-first APIs on oRPC
  1.15.4 (`.plans/openapi-contracts.md`). `apiHandlers` mounts an oRPC router in one TanStack Start
  server route with the generated OpenAPI 3.1 document (`/api/openapi.json`) and its reference
  page (`/api/doc`); `contractClient` calls any contract with every response validated;
  `isomorphicClient` gives an app one client for its own contract on both sides; `coverageProblems`
  and `apiChecks` fail on a procedure without a route, a policy or documented errors;
  `reservationApiChecks` covers the demo reservation over HTTP. New dependencies: `@orpc/client`,
  `@orpc/contract`, `@orpc/openapi`, `@orpc/openapi-client`, `@orpc/server`, `@orpc/zod`, all
  1.15.4; `@tanstack/react-start` is a new optional peer.

* `./reservation`: `reservationFieldErrors` and `reservationConfirmation`, the wire shapes a
  contract declares for a rejected and an accepted reservation.

* Paraglide's `routeStrategies` keep `/api/*` out of URL localisation: no redirect, and the
  language comes from Accept-Language, else the base locale.

### Changed [#changed-9]

* One zone badge style (secondary) on site and app pages; the app pages no longer repeat it as a
  label; site pages have no back links (they navigate through the header).
* `./reservation` sets Zod's `jitless` option, so Zod never probes for eval under a strict CSP.
* `zoneChecks` accepts a `nonce` attribute on the app pages' robots meta.
* `showcase/status-card.checks`: `statusCardChecks` takes `endpoint`, the path the card asks for
  the status; without it, any server function as before.

## [0.10.3] - 2026-09-25 [#0103---2026-09-25]

### Added [#added-7]

* `./reservation`: the demo reservation's rules as one Zod 4 schema (`reservationSchema(locale)`,
  localized messages) for the browser and the server, the server function's input shape
  (`reservationInput`) and `reservationErrors` for a server's field errors.

### Changed [#changed-10]

* `showcase/search-params`: the formats search params are validated by a Zod 4 schema,
  `formatsSearchSchema`, which TanStack Router takes directly as `validateSearch` (Standard
  Schema, no adapter). It replaces the hand-written `validateSearch` function and its parsing
  helpers; `FormatsSearch` is the schema's output type. Written with Zod Mini to keep the entry
  chunk small. New dependency: `zod` 4.6.5.
* `DemoPage`'s form runs on TanStack Form (`@tanstack/react-form` 1.33.5) with shadcn's Field
  pattern: the shared schema validates on submit, a server's field errors show as the form's own,
  and `onDirtyChange` follows the form's `isDirty`. Its own validation code and input tracking are
  gone; `Reservation` and `ReservationResult` now come from `./reservation` (still re-exported).

## [0.10.2] - 2026-09-25 [#0102---2026-09-25]

### Changed [#changed-11]

* Formats in five sections (this language, dates and times, numbers, money, words) with a list of
  links to them; each search-param control sits in the section it changes. `FormatsExtras` slots are
  now rows in groups (`language`, `systems`, `dates`, `currency`) and cards per section (`time`,
  `numbers`, `money`, `words`); `FormatsControls` and `PrerenderedFormatsControls` become
  `choiceCards` and `prerenderedChoiceCards` (one `ChoiceCard` per param, with `to`).
* Full width in both frames, as shadcn's sidebar-16 block has it; formats cards two per row on
  medium screens and three on wide ones.

## [0.10.1] - 2026-09-25 [#0101---2026-09-25]

### Added [#added-8]

* Formats as a site page and an app page: `FormatsContent` (the page's content once),
  `FormatsPage` (site frame) and `AppFormatsPage` (app frame); `/app/formats` in `appPaths` and the
  app sidebar; `FormatsControls` takes the page it belongs to (`to`).
* `LanguageMenu`: the app pages' language picker, shadcn's DropdownMenu with a radio group; choosing
  calls Paraglide's `setLocale`. Site pages keep the plain links.
* `zoneChecks`: on a phone in landscape, the way back to the site stays in view.

### Changed [#changed-12]

* The app sidebar's "Back to the site" moves into `SidebarFooter`, so it stays in view on short
  screens.
* `performanceChecks` judges the median of five runs (Lighthouse's `computeMedianRun`).
* `demoChecks` switches language through the app's menu.

## [0.10.0] - 2026-09-25 [#0100---2026-09-25]

All in on shadcn, and site pages kept apart from app pages. Breaking for consumers.

### Changed [#changed-13]

* shadcn's monorepo layout: the app's `components.json` routes `shadcn add` into this package; the
  stylesheet is `globals.css` (was `styles.css`), exactly what the shadcn CLI writes (default Nova
  style, neutral theme, Geist), checked by `mise run ui:verify` before every release.
* Components regenerated with shadcn's RTL mode; `direction` (DirectionProvider), `skeleton`,
  `empty`, `sidebar`, `sheet`, `tooltip`, `breadcrumb`, `collapsible`, `dropdown-menu`, `avatar` and
  the `use-mobile` hook added through the CLI.
* `fonts.css`: Geist from shadcn, Noto Sans Arabic on Arabic pages per shadcn's RTL guide, generic
  code font; apps add fontaine's size-matched fallbacks in their Vite config.
* `paths`: `sitePaths` (for Google: no JavaScript needed, indexed, in the sitemap), `appPaths`
  (under `/app`: JavaScript, noindex) and `allPaths`, replacing `publicPaths`; `pageHead` adds
  noindex to app pages.
* `pages`: `SiteShell` (static shadcn parts), `ZoneBadge`, `SkipLink`, `Intro`; the demo moves to
  `app-pages` with `AppShell` (shadcn's sidebar-16 block, owned in `blocks/sidebar-16`),
  `AppHomePage` and `LocationPage`.
* `publicPageChecks` enforces that every named font is loaded; new `zoneChecks`; checks find page
  links inside `#main`; `codeSplittingChecks` takes a start page per zone.

## [0.9.3] - 2026-09-25 [#093---2026-09-25]

### Added [#added-9]

* `showcase/device-place`: `DevicePlace`, the device's own location from the Geolocation API,
  asked only when the visitor presses its button, explained before asking, never sent anywhere;
  with Cloudflare's location it also shows the distance between the two. `devicePlaceChecks`.
* `cloudflare`: `Place` carries Cloudflare's `latitude` and `longitude` when valid.
* `worker`: every response sends `Permissions-Policy: geolocation=(self), camera=(), microphone=()`,
  asserted by `observabilityChecks`.

## [0.9.2] - 2026-09-25 [#092---2026-09-25]

### Added [#added-10]

* `showcase/search-params`: `PrerenderedFormatsControls`, the formats controls for a prerendered
  page (static defaults in the HTML, the address's values once hydrated, through TanStack's
  `ClientOnly`), and `FormatsControls`' `interactive` option behind it.
* `checkedLocales` in `@joeblew999/remy-ui/checks`: every locale, or the subset in `CHECK_LOCALES`;
  every per-language check iterates it, so the shared `project:test:quick` tier can run the checks
  on a few representative languages.

### Changed [#changed-14]

* `statusCardChecks` jumps the refresh interval with Playwright's clock instead of waiting it out
  (about 10 s to under 1 s).

## [0.9.1] - 2026-09-25 [#091---2026-09-25]

### Fixed [#fixed-1]

* `DemoPage` notices input typed before hydration (a prerendered page fires no `onInput` for it),
  so the leave warning still guards it.
* `demoChecks`, `navigationBlockingChecks` and `codeSplittingChecks` act only once React has
  hydrated the element, instead of racing hydration on prerendered pages.

### Added [#added-11]

* `hydrated(locator)` in `@joeblew999/remy-ui/checks`: resolves once React has hydrated an element.

## [0.9.0] - 2026-09-25 [#090---2026-09-25]

The move to TanStack Start, Router and Query, with the TanStack showcase ([plan](.plans/done/tanstack.md)).
Replaces React Router: consumers move their routes to TanStack file routes (see remy-auth and
remy-auth-app).

### Added [#added-12]

* `@joeblew999/remy-ui/tanstack`: `localizedWorker(service, start)`, the Worker entry for a
  server-rendered Start app (`withObservability` around Paraglide's middleware around Start's
  handler, which gets the original request so its Cloudflare `cf` properties reach server functions;
  un-localized entry URLs answer 302 with `Vary`; HTML is `no-store`); `entryRedirect`;
  `localeRewrite`, the router `rewrite` (Paraglide's `deLocalizeUrl`/`localizeUrl`);
  `pageHead({ path, title, description })` for a route's `head()`: title, description,
  self-canonical and reciprocal hreflang; `suggestedLocale(request)` and
  `suggestedLocaleInBrowser(page)` for the language hint.
* `DemoPage` takes optional `onReserve` (called once the form's own validation passes; its
  field errors or confirmation message are shown) and `onDirtyChange` (unsaved input), and
  exports the `Reservation` and `ReservationResult` types. Without them it behaves as before.
* Export patterns `./showcase/*` (`src/showcase/*.tsx`) and `./showcase/*.checks`
  (`src/showcase/*.checks.js`) for the TanStack showcase's components and checks.
* `worker`: the inner handler receives the generated request ID as `X-Request-ID` (a client's
  own value is replaced); new exports `logContext`, `writeLog`, `outcome`, `level` and
  `requestIdHeader`, so the log contract has one definition.
* Showcase modules: `showcase/search-params` (`validateSearch`, `searchDefaults`,
  `calendarsFor`, `FormatsControls`), `showcase/navigation-blocking` (`useLeaveGuard`) and
  `showcase/time-zone` (`TimeZonePage`, `canonicalTimeZone`, `timeZoneName`, `timeZonePath`).
* Showcase checks: `search-params`, `preload`, `navigation-blocking`, `server-functions`,
  `deferred-place`, `status-card`, `problem` (localized 404 for an unknown sub-resource, error
  page without leaks and retry, read-only server routes with caching and 405),
  `code-splitting` and `build-boundaries` (`serverOnlyMarkers`, `devtoolsMarkers`).
* Catalog keys for the search-param controls, the leave-page warning, the live status card, the
  retry button and the time zone page.

### Changed [#changed-15]

* `pages`: in-app links are TanStack `Link`s to de-localized paths with `preload="intent"`;
  the router's rewrite adds the locale. Language changes stay plain anchors (full navigations).
* Peer dependency `react-router` replaced by `@tanstack/react-router` (optional).
* `HomePage` takes `children`, shown inside the page under its links (the live status card).
* `LanguageHint` puts its two actions under the text instead of shadcn's absolutely placed
  `AlertAction`, which overlapped the text at phone width.
* `DemoPage` shows the localized "Please try again." when `onReserve` rejects, instead of an
  unhandled rejection.
* `performanceChecks` no longer warms a page before Lighthouse measures it. The warm-up hid a
  first-layout stall of seconds that every visitor paid in a fresh Chrome renderer on macOS; the
  cause was font-family names that never load (`Inter`, `ui-monospace`, `SFMono-Regular`, ...),
  fixed by the new `fonts.css` export (generic families only: `system-ui, sans-serif` and
  `monospace`), which each app imports after `styles.css`.
* `publicPageChecks` fails when any element on any page uses a non-generic font family or the
  page declares a web font.

### Removed [#removed]

* `@joeblew999/remy-ui/react-router` (`languageMiddleware`, `redirectToLocalized`, `pageMeta`,
  `requireLocale`, `suggestedLocale`); routes no longer carry a `:locale` segment.

## [0.8.0] - 2026-09-24 [#080---2026-09-24]

### Added [#added-13]

* `@joeblew999/remy-ui/worker`: `withObservability(service, handler)` wraps any Worker's
  fetch: `X-Request-ID` on every response, one structured log line per request following the
  shared contract (`schemaVersion`, `service`, `environment`, `release` from the version
  metadata binding, `event`, `level`, `requestId`, route template, `method`, `status`,
  `outcome`, `reasonCode` on failures, never URLs or headers), and `/healthz` for liveness.
* `observabilityChecks({ service, paths })` in the shared checks.

## [0.7.0] - 2026-09-24 [#070---2026-09-24]

### Added [#added-14]

* `@joeblew999/remy-ui/pages`: `Shell`, `HomePage`, `DemoPage`, `FormatsPage` (with slots
  for an app's extra rows and sections), `Group` and `Row`: the pages the shared checks
  test, so both apps render the same markup instead of keeping copies.
* `@joeblew999/remy-ui/paths`: `publicPaths` as plain JavaScript for route configs and specs.
* `requireLocale` in `@joeblew999/remy-ui/react-router`.

## [0.6.0] - 2026-09-24 [#060---2026-09-24]

### Changed [#changed-16]

* `playwrightConfig()` splits checks into two levels: `ours` (the app's own checks, fast)
  and `google` plus `google-cwv` (Lighthouse audits and Core Web Vitals, slow). The shared
  `project:test` runs level 1; `project:test:google` runs level 2; `project:test:remote`
  runs both against a deployment.

## [0.5.0] - 2026-09-24 [#050---2026-09-24]

### Added [#added-15]

* `performanceChecks` in `@joeblew999/remy-ui/checks`: Core Web Vitals through Google's
  `lighthouse` package (optional peer) over Playwright's Chrome, gated on Google's "good"
  thresholds (LCP 2.5 s, CLS 0.1, TBT 200 ms) and a Performance score of at least 0.9,
  with the HTML report attached. The Chrome DevTools CLI excludes that category by design.
  `playwrightConfig()` runs `tests/performance.spec.ts` alone after every other file, so
  parallel browsers cannot inflate the timings, and Lighthouse measures a page the check
  has already warmed, since a fresh browser's cold font scan is not a page cost.

### Changed [#changed-17]

* Every component in `src/components` is generated by the pinned shadcn CLI from the
  official `base-nova` registry (button, card, input, label, badge, alert, separator,
  field); `mise run ui:components` regenerates them and the gate fails on any drift.
  Exported as `@joeblew999/remy-ui/components/*`.
* `LanguageSwitcher` and `LanguageHint` are built from those components (`Alert`,
  `Button`) and Tailwind utilities; the package ships no component CSS of its own.

## [0.4.0] - 2026-09-24 [#040---2026-09-24]

### Added [#added-16]

* `@joeblew999/remy-ui/playwright`: `playwrightConfig()`, the shared Playwright configuration
  (local target on Cloudflare's local host at `PREVIEW_PORT`, remote target from
  `TEST_BASE_URL`, per-target HTML reports), so a project's config is one call.

## [0.3.0] - 2026-09-24 [#030---2026-09-24]

### Added [#added-17]

* `@joeblew999/remy-ui/checks`: shared Playwright checks (`publicPageChecks`, `entryChecks`,
  `demoChecks`, `formatsChecks`, `lighthouseChecks`, plus `collectErrors`, `endonym`,
  `direction`, `localizedPath`) so every app built on the package runs the same
  Google-facing checks; `@playwright/test` is an optional peer.
* `@joeblew999/remy-ui/samples`: the fixed sample values the formats and demo pages render
  and the checks expect.

## [0.2.0] - 2026-09-24 [#020---2026-09-24]

### Added [#added-18]

* Paraglide strategies `url`, `cookie`, `preferredLanguage`, `baseLocale` with URL patterns
  that keep every locale prefixed; `@joeblew999/remy-ui/locale` re-exports the runtime's
  `getLocale`, `setLocale`, `localizeHref`, `localizeUrl`, `deLocalizeHref`, `cookieName`
  and text `direction`.
* `@joeblew999/remy-ui/language`: `LanguageSwitcher` and `LanguageHint` on Paraglide's
  localized hrefs and `setLocale`, with their styles in `styles.css`.
* `@joeblew999/remy-ui/react-router`: `languageMiddleware` (Paraglide's middleware as root
  middleware), `suggestedLocale`, `redirectToLocalized` and `pageMeta`; `react-router`
  is an optional peer.
* `@joeblew999/remy-ui/seo`: `alternates` built from Paraglide's URL patterns.
* `@joeblew999/remy-ui/client`: `useSuggestedLocale` and `DeviceTime` for prerendered apps.
* `@joeblew999/remy-ui/cloudflare`: `placeFromCloudflare`.
* `@joeblew999/remy-ui/runtime`: the generated runtime as plain JavaScript for build configs.

### Changed [#changed-18]

* The compiler options live in `packages/ui/paraglide.mjs`, shared by the Vite plugin and
  `mise run ui:generate`. The remembered-choice cookie is Paraglide's `PARAGLIDE_LOCALE`.

## [0.1.0] - 2026-09-24 [#010---2026-09-24]

### Added [#added-19]

* `@joeblew999/remy-ui/button`: the shadcn `base-nova` / Base UI button with Remy's variants.
* `@joeblew999/remy-ui/styles.css`: Remy's stone/orange theme tokens for light and dark mode.
* `@joeblew999/remy-ui/messages`: compiled Paraglide catalogs for English, Spanish and
  Arabic, including `number`, `datetime`, `relativetime` and `plural` formatters. The
  Arabic catalog is agent-authored and not yet reviewed.
* `@joeblew999/remy-ui/locale`: the locale list, `isLocale`, `baseLocale`, reading
  `direction` and endonym `localeName` from Intl.
* `@joeblew999/remy-ui/locale-info`: a locale's calendars, numbering system, hour cycle
  and week conventions, plus `weekdayName`.

[Unreleased]: https://github.com/joeblew999/remy-auth/compare/v0.10.4...HEAD

[0.10.4]: https://github.com/joeblew999/remy-auth/compare/v0.10.3...v0.10.4

[0.10.3]: https://github.com/joeblew999/remy-auth/compare/v0.10.2...v0.10.3

[0.10.2]: https://github.com/joeblew999/remy-auth/compare/v0.10.1...v0.10.2

[0.10.1]: https://github.com/joeblew999/remy-auth/compare/v0.10.0...v0.10.1

[0.10.0]: https://github.com/joeblew999/remy-auth/compare/v0.9.3...v0.10.0

[0.9.3]: https://github.com/joeblew999/remy-auth/compare/v0.9.2...v0.9.3

[0.9.2]: https://github.com/joeblew999/remy-auth/compare/v0.9.1...v0.9.2

[0.9.1]: https://github.com/joeblew999/remy-auth/compare/v0.9.0...v0.9.1

[0.9.0]: https://github.com/joeblew999/remy-auth/compare/v0.8.0...v0.9.0

[0.8.0]: https://github.com/joeblew999/remy-auth/compare/v0.7.0...v0.8.0

[0.7.0]: https://github.com/joeblew999/remy-auth/compare/v0.6.0...v0.7.0

[0.6.0]: https://github.com/joeblew999/remy-auth/compare/v0.5.0...v0.6.0

[0.5.0]: https://github.com/joeblew999/remy-auth/compare/v0.4.0...v0.5.0

[0.4.0]: https://github.com/joeblew999/remy-auth/compare/v0.3.0...v0.4.0

[0.3.0]: https://github.com/joeblew999/remy-auth/compare/v0.2.0...v0.3.0

[0.2.0]: https://github.com/joeblew999/remy-auth/compare/v0.1.0...v0.2.0

[0.1.0]: https://github.com/joeblew999/remy-auth/releases/tag/v0.1.0
