@easygov/react-components 0.12.0 → 0.14.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
@@ -121,6 +121,27 @@ app. An absent permission never means "allowed".
121
121
  The header refetches the context whenever the URL's pathname changes, including client-side router
122
122
  navigations; a change of only the query string or fragment does not refetch.
123
123
 
124
+ #### The context is renewed before it expires
125
+
126
+ `contextJwt` is short-lived: core-backend signs it with an `exp` (5 minutes by default). Without a
127
+ renewal, a page that stays on one URL would send an expired token to its backend. So the header
128
+ fetches a new context about 60 seconds before `exp` and keeps doing so for as long as the user is
129
+ signed in. Plan for these consequences:
130
+
131
+ - **Forward `contextJwt` fresh.** Read it from the hook (or the latest event) when you make a
132
+ request; don't capture it once at mount.
133
+ - **A renewal is not a change.** Each renewal delivers a new `contextJwt`, but when the context
134
+ itself is unchanged, `claims` is the **same object** as before. An effect or memo keyed on
135
+ `claims` therefore does not re-run, and a form you prefilled from it keeps what the user typed.
136
+ Read `claims` for what the context says, `contextJwt` for the token.
137
+ - **Never reset user input from `onContextChange` or the `contextchange` event** without checking
138
+ whether the content changed (below). Both fire on every renewal, roughly every 4 minutes.
139
+ - **A failed renewal is retried quietly** every 15 seconds while the old token is still valid.
140
+ Only if the token expires without a successful renewal, or core refuses the request for good
141
+ (for example `customer-account-not-accessible`), the header shows its error dialog, once per
142
+ outage. The previous `claims` stay in place meanwhile. A failed fetch after a navigation shows
143
+ the dialog at once and is then retried the same way; a refusal for good is not retried.
144
+
124
145
  `claims` is `null` until the first response lands and again after logout — render a fallback,
125
146
  don't assume it is present on first paint. The hook reflects the last context an `EasygovHeader`
126
147
  resolved; it never fetches on its own, and it is not cleared when the header unmounts. Claims
@@ -131,10 +152,22 @@ Outside React — including `<eg-easygov-header>` — listen for the event inste
131
152
 
132
153
  ```js
133
154
  document.addEventListener('contextchange', (e) => {
134
- const { contextJwt, claims } = e.detail;
155
+ const { contextJwt, claims, contentChanged } = e.detail;
156
+ if (contentChanged) {
157
+ prefillForm(claims); // a real change: new account, process, ...
158
+ }
159
+ // Always keep the newest token for requests to your backend.
160
+ latestContextJwt = contextJwt;
135
161
  });
136
162
  ```
137
163
 
164
+ `contentChanged` is `true` for the first context after sign-in and whenever `claims` differs from
165
+ the previous event; it is `false` when the event only delivers a renewed token. Prefill only when
166
+ it is `true`, otherwise every renewal overwrites what the user has typed since. In TypeScript the
167
+ detail is typed as `HeaderContextChangeDetail`, exported by both `@easygov/react-components` and
168
+ `@easygov/web-components`. The `onContextChange` callback has no such flag —
169
+ compare `claims` by identity there (`claims !== previousClaims`).
170
+
138
171
  **The claims are decoded, not verified.** Use them for prefilling and rendering. Any backend
139
172
  that receives `contextJwt` must verify its signature against core-backend's published JWKS
140
173
  before trusting a claim.
@@ -453,6 +453,21 @@ interface HeaderContextClaims {
453
453
  */
454
454
  parentProcessId?: string;
455
455
  }
456
+ /**
457
+ * `detail` of the `contextchange` CustomEvent. The event fires for every new JWT, which includes
458
+ * the background refresh that renews it shortly before it expires; `contentChanged` says whether
459
+ * `claims` differs from what the previous event delivered.
460
+ */
461
+ interface HeaderContextChangeDetail {
462
+ contextJwt: string;
463
+ claims: HeaderContextClaims;
464
+ /**
465
+ * `true` for the first context of a session and whenever `claims` differs from the previous
466
+ * event's. `false` for a refresh that only renewed the token: prefilling a form from `claims`
467
+ * on such an event would overwrite what the user has typed since.
468
+ */
469
+ contentChanged: boolean;
470
+ }
456
471
 
457
472
  interface EasygovHeaderContext {
458
473
  contextJwt: string | null;
@@ -598,6 +613,11 @@ declare function useEasygovAuthStatus(): AuthStatus;
598
613
  * still describe a previously selected account after the URL has moved on. Only sign-out (or a
599
614
  * failed *first* fetch) leaves `claims` at `null`.
600
615
  *
616
+ * `contextJwt` is renewed shortly before it expires (5 minutes by default), so it changes about
617
+ * every 4 minutes while the page stays put. `claims` keeps its identity across a renewal that
618
+ * changed nothing else, so an effect or memo keyed on `claims` does not re-run — read
619
+ * `contextJwt` when forwarding the token, `claims` when rendering or prefilling.
620
+ *
601
621
  * IMPORTANT — trust boundary: `claims` is decoded, NOT signature-verified. Use it to prefill
602
622
  * forms and drive rendering; never to authorize. A backend receiving `contextJwt` MUST verify it
603
623
  * against core-backend's published JWKS.
@@ -629,6 +649,14 @@ interface EasygovHeaderProps {
629
649
  * `header-context` endpoint (mirrored by the `contextchange` CustomEvent
630
650
  * dispatched on the header element), together with its decoded `claims`.
631
651
  *
652
+ * IMPORTANT — fires on every renewal, not only when the context changes. The JWT is short-lived
653
+ * (5 minutes by default), so the header fetches a new one shortly before it expires; that
654
+ * arrives here as a new `contextJwt`. When the refreshed context equals the previous one,
655
+ * `claims` is the very same object as in the previous call, so `claims !== previousClaims`
656
+ * tells a real change from a renewal. Never reset user input (a prefilled form) from this
657
+ * callback without that check. The `contextchange` event carries the same answer as
658
+ * `detail.contentChanged`.
659
+ *
632
660
  * Both are always present when this fires: a payload that fails to decode never produces a
633
661
  * `contextJwt`, so a decode failure suppresses the call rather than delivering null claims.
634
662
  *
@@ -688,4 +716,4 @@ declare function getEasygovDisplayLanguage(): Locale;
688
716
  declare function setEasygovDisplayLanguage(locale: Locale): void;
689
717
  declare function subscribeEasygovDisplayLanguage(listener: () => void): () => void;
690
718
 
691
- export { type AuthStatus, BrandBase, BrandEasygov, BrandFacebook, BrandKdk, BrandLinkedin, type BrandProps, BrandSeg, BrandSgv, BrandSsv, BrandSwiss, BrandXing, BrandYoutube, Button, type ButtonProps, type DesktopSpan, Dropdown, DropdownChip, DropdownChipsOverflow, type DropdownChipsOverflowProps, DropdownChipsTrigger, type DropdownChipsTriggerProps, DropdownCollection, DropdownEmpty, DropdownGroup, DropdownGroupLabel, DropdownHelperText, type DropdownHelperTextProps, DropdownInput, DropdownItem, type DropdownItemProps, DropdownItemText, DropdownLabel, type DropdownLabelProps, DropdownList, DropdownPopup, type DropdownPopupProps, DropdownSeparator, DropdownToggle, DropdownTrigger, type DropdownTriggerProps, DropdownValue, EasygovFooter, EasygovHeader, type EasygovHeaderContext, type EasygovHeaderProps, type EasygovSession, type EasygovVersionInfo, ErrorDialog, type ErrorDialogProps, Grid, GridItem, type GridItemProps, type GridProps, type AccountVerificationStatus as HeaderContextAccountVerificationStatus, type HeaderContextClaims, type IndividualAccount as HeaderContextIndividualAccount, type ManagementRole as HeaderContextManagementRole, type ManagementRoleStatus as HeaderContextManagementRoleStatus, type ManagementRoleType as HeaderContextManagementRoleType, type OrganizationAccount as HeaderContextOrganizationAccount, type PermissionLevel as HeaderContextPermissionLevel, type ProcessStatus as HeaderContextProcessStatus, type ServiceApp as HeaderContextServiceApp, type ServicePermission as HeaderContextServicePermission, type UserProfile as HeaderContextUserProfile, Heading, type HeadingProps, Input, type InputProps, type Locale, type MobileSpan, NavigationMenu, NavigationMenuAnchor, type NavigationMenuAnchorProps, NavigationMenuContent, type NavigationMenuContentProps, NavigationMenuItem, type NavigationMenuItemProps, NavigationMenuLink, type NavigationMenuLinkProps, NavigationMenuList, type NavigationMenuListProps, type NavigationMenuProps, NavigationMenuTrigger, type NavigationMenuTriggerProps, RequireCustomerAccount, type RequireCustomerAccountProps, RequireSession, type RequireSessionProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectGroupLabel, type SelectGroupLabelProps, SelectHelperText, type SelectHelperTextProps, SelectItem, type SelectItemProps, SelectLabel, type SelectLabelProps, SelectSeparator, type SelectSeparatorProps, SelectTrigger, type SelectTriggerProps, type SelectedCustomerAccount, type SelectedProcess, type SessionUser, type TabletSpan, Text, TextLink, type TextLinkProps, type TextProps, buttonVariants, getAuthStatus, getEasygovDisplayLanguage, headingVariants, requireSession, setEasygovBusinessModuleVersion, setEasygovDisplayLanguage, subscribeEasygovDisplayLanguage, textLinkVariants, textVariants, useEasygovAuthStatus, useEasygovDisplayLanguage, useEasygovHeaderContext, useEasygovSession, useEasygovVersionInfo, useRequireCustomerAccount };
719
+ export { type AuthStatus, BrandBase, BrandEasygov, BrandFacebook, BrandKdk, BrandLinkedin, type BrandProps, BrandSeg, BrandSgv, BrandSsv, BrandSwiss, BrandXing, BrandYoutube, Button, type ButtonProps, type DesktopSpan, Dropdown, DropdownChip, DropdownChipsOverflow, type DropdownChipsOverflowProps, DropdownChipsTrigger, type DropdownChipsTriggerProps, DropdownCollection, DropdownEmpty, DropdownGroup, DropdownGroupLabel, DropdownHelperText, type DropdownHelperTextProps, DropdownInput, DropdownItem, type DropdownItemProps, DropdownItemText, DropdownLabel, type DropdownLabelProps, DropdownList, DropdownPopup, type DropdownPopupProps, DropdownSeparator, DropdownToggle, DropdownTrigger, type DropdownTriggerProps, DropdownValue, EasygovFooter, EasygovHeader, type EasygovHeaderContext, type EasygovHeaderProps, type EasygovSession, type EasygovVersionInfo, ErrorDialog, type ErrorDialogProps, Grid, GridItem, type GridItemProps, type GridProps, type AccountVerificationStatus as HeaderContextAccountVerificationStatus, type HeaderContextChangeDetail, type HeaderContextClaims, type IndividualAccount as HeaderContextIndividualAccount, type ManagementRole as HeaderContextManagementRole, type ManagementRoleStatus as HeaderContextManagementRoleStatus, type ManagementRoleType as HeaderContextManagementRoleType, type OrganizationAccount as HeaderContextOrganizationAccount, type PermissionLevel as HeaderContextPermissionLevel, type ProcessStatus as HeaderContextProcessStatus, type ServiceApp as HeaderContextServiceApp, type ServicePermission as HeaderContextServicePermission, type UserProfile as HeaderContextUserProfile, Heading, type HeadingProps, Input, type InputProps, type Locale, type MobileSpan, NavigationMenu, NavigationMenuAnchor, type NavigationMenuAnchorProps, NavigationMenuContent, type NavigationMenuContentProps, NavigationMenuItem, type NavigationMenuItemProps, NavigationMenuLink, type NavigationMenuLinkProps, NavigationMenuList, type NavigationMenuListProps, type NavigationMenuProps, NavigationMenuTrigger, type NavigationMenuTriggerProps, RequireCustomerAccount, type RequireCustomerAccountProps, RequireSession, type RequireSessionProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectGroupLabel, type SelectGroupLabelProps, SelectHelperText, type SelectHelperTextProps, SelectItem, type SelectItemProps, SelectLabel, type SelectLabelProps, SelectSeparator, type SelectSeparatorProps, SelectTrigger, type SelectTriggerProps, type SelectedCustomerAccount, type SelectedProcess, type SessionUser, type TabletSpan, Text, TextLink, type TextLinkProps, type TextProps, buttonVariants, getAuthStatus, getEasygovDisplayLanguage, headingVariants, requireSession, setEasygovBusinessModuleVersion, setEasygovDisplayLanguage, subscribeEasygovDisplayLanguage, textLinkVariants, textVariants, useEasygovAuthStatus, useEasygovDisplayLanguage, useEasygovHeaderContext, useEasygovSession, useEasygovVersionInfo, useRequireCustomerAccount };