Postboy Help

React

Postboy integrates naturally with React’s component model, hooks, and RxJS-based subscriptions. This guide focuses on React-specific integration: how to create the bus, how to activate registrators at the right time, how to use React Context when a singleton is not enough, and how to avoid common lifecycle issues with effects, Strict Mode, and server-side rendering.

For general Postboy concepts, see:

Installation

Install Postboy with npm:

npm install @artstesh/postboy@3

Postboy is published in major lines that follow the RxJS generation used by your project:

Postboy branch

RxJS version

Typical usage

1.x

^6

Older RxJS projects

3.x

^7

Current projects using RxJS 7

4.x

^8

Upcoming line for projects using RxJS 8

For most current React projects using RxJS 7, use the 3.x line.

When your project moves to RxJS 8, use the 4.x line:

npm install @artstesh/postboy@3

For more details about versioning, see Versions.

React integration model

React does not have a built-in dependency injection container. Because of that, Postboy integration is usually based on one of two patterns:

  1. A module-level singleton bus.
    The simplest option. It works well for many client-side React applications.

  2. A React Context provider.
    A more explicit option. It is useful when you need isolated bus instances, SSR-aware setup, microfrontend boundaries, or easier replacement in tests.

Registrators still play the same role as in other environments:

  • up() activates registrations;

  • down() cleans lifecycle-bound subscriptions and registrations.

In React, the main task is to align up() and down() with the correct React lifetime.

The simplest client-side setup

For a regular client-side React application, the simplest setup is:

  1. create one PostboyService instance;

  2. create one root registrator;

  3. activate the root registrator before rendering the React tree;

  4. use useEffect for component subscriptions.

This avoids the most common error:

There is no registered event

That error usually means that a component tried to subscribe or publish before the corresponding message channel was registered.

Step 1. Create a singleton bus

Create the bus in a separate module:

// postboy.ts import {PostboyService} from '@artstesh/postboy'; export const postboy = new PostboyService();

This singleton becomes the application-wide message bus.

Do not create the bus inside a React component body:

// Wrong: a new bus may be created during rendering. import {PostboyService} from '@artstesh/postboy'; export function App() { const postboy = new PostboyService(); return <div/>; }

React components can render many times. The bus must have a stable lifetime.

Step 2. Create a root registrator

A root registrator is useful for application-wide communication: authentication state, theme changes, global notifications, diagnostics, and other cross-cutting concerns.

// root-registrator.ts import {PostboyAbstractRegistrator} from '@artstesh/postboy'; import {postboy} from './postboy'; import {ButtonClickedEvent} from './messages/events/ButtonClickedEvent'; export class RootRegistrator extends PostboyAbstractRegistrator { constructor() { super(postboy); } protected _up(): void { this.recordSubject(ButtonClickedEvent); } }

Keep the root registrator small. It should contain only messages and handlers that are truly global.

For details about registration methods, see PostboyAbstractRegistrator.

Step 3. Activate the root registrator before rendering React

If child components subscribe immediately after mounting, activating the root registrator in App.useEffect() may be too late.

A reliable first setup is to activate the root registrator before calling render(...).

// main.tsx import React from 'react'; import ReactDOM from 'react-dom/client'; import {App} from './App'; import {RootRegistrator} from './root-registrator'; const rootRegistrator = new RootRegistrator(); rootRegistrator.up(); ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <App/> </React.StrictMode> );

The order is explicit:

  1. create the bus;

  2. activate the root registrator;

  3. render the React application;

  4. components can safely subscribe to registered root messages.

This is the recommended minimal setup for a simple client-side SPA.

If you use hot module replacement, tests, or non-standard application bootstrap, make sure to call rootRegistrator.down() when the application is disposed.

Step 4. Subscribe from a component

Postboy subscriptions are RxJS subscriptions. Use useEffect and unsubscribe in the cleanup function.

// EventDisplay.tsx import {useEffect, useState} from 'react'; import {postboy} from './postboy'; import {ButtonClickedEvent} from './messages/events/ButtonClickedEvent'; export function EventDisplay() { const [logs, setLogs] = useState<string[]>([]); useEffect(() => { const subscription = postboy.sub(ButtonClickedEvent).subscribe(event => { setLogs(previous => [ `[${new Date().toLocaleTimeString()}] ${event.buttonName} clicked`, ...previous ]); }); return () => { subscription.unsubscribe(); }; }, []); return ( <ul> {logs.map((log, index) => ( <li key={index}>{log}</li> ))} </ul> ); }

Another component can publish the event from an event handler:

// DemoButton.tsx import {postboy} from './postboy'; import {ButtonClickedEvent} from './messages/events/ButtonClickedEvent'; export function DemoButton() { const handleClick = () => { postboy.fire(new ButtonClickedEvent('Demo button')); }; return ( <button onClick={handleClick}> Click me </button> ); }

Do not call fire(...), fireCallback(...), or other side-effecting bus methods during render. Use event handlers, effects, or application services.

Why not just use useLayoutEffect in App?

It may be tempting to activate the root registrator inside App with useLayoutEffect:

export function App() { useLayoutEffect(() => { rootRegistrator.up(); return () => { rootRegistrator.down(); }; }, []); return <Application/>; }

This can work in some cases because useLayoutEffect runs earlier than useEffect. However, it should not be the default solution for Postboy registration.

Prefer activating global registrations before rendering the React tree when:

  • root messages are used by many child components;

  • child components subscribe immediately in useEffect;

  • you want a predictable bootstrap order;

  • you are building a simple client-side SPA.

Use useLayoutEffect only when you specifically need React layout timing. Postboy registration is usually an application bootstrap concern, not a layout concern.

Registration order matters

Postboy channels and executor handlers must be registered before they are used.

If a component or service-like module calls fire, sub, fireCallback, or exec before the corresponding registration exists, Postboy can throw an error such as:

There is no registered event ButtonClickedEvent

In React this usually means one of the following:

  • the root registrator was never created;

  • registrator.up() was not called;

  • a component subscribed before the registrator was activated;

  • a message was registered in a feature registrator, but used outside that feature scope;

  • the bus was created more than once;

  • the message class was imported through different runtime paths;

  • code used the bus during render before setup was complete.

The safe rule is simple:

  1. create the bus once;

  2. create the registrator for the correct scope;

  3. call up();

  4. only then publish, subscribe, call callbacks, or execute handlers;

  5. call down() when the scope ends.

For more about this lifecycle model, see Lifecycle concepts.

When to use React Context

The singleton setup is intentionally simple. It is a good starting point for many browser-only applications.

Use React Context when you need more control over bus ownership.

Context is useful for:

  • SSR frameworks;

  • tests that replace the bus;

  • multiple independent buses;

  • isolated widgets;

  • microfrontends;

  • feature-level bus ownership;

  • avoiding module-level singletons.

With Context, you do not import a global postboy instance directly. Instead, React provides the bus through a PostboyProvider, and components access it through a hook.

Creating PostboyContext

Create a context module:

// postboy/PostboyContext.tsx import { createContext, ReactNode, useContext, useMemo } from 'react'; import {PostboyService} from '@artstesh/postboy'; const PostboyContext = createContext<PostboyService | null>(null); export function PostboyProvider({children}: { children: ReactNode }) { const postboy = useMemo(() => new PostboyService(), []); return ( <PostboyContext.Provider value={postboy}> {children} </PostboyContext.Provider> ); } export function usePostboy(): PostboyService { const postboy = useContext(PostboyContext); if (!postboy) { throw new Error('usePostboy must be used within PostboyProvider'); } return postboy; }

PostboyProvider creates one bus for the subtree inside the provider.

usePostboy() is a convenience hook that gives any child component access to that bus.

Using PostboyProvider

Wrap your application with PostboyProvider.

// main.tsx import React from 'react'; import ReactDOM from 'react-dom/client'; import {App} from './App'; import {PostboyProvider} from './postboy/PostboyContext'; ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <PostboyProvider> <App/> </PostboyProvider> </React.StrictMode> );

Now any component under PostboyProvider can access the bus:

// SomeComponent.tsx import {usePostboy} from './postboy/PostboyContext'; export function SomeComponent() { const postboy = usePostboy(); return ( <button onClick={() => postboy.fire(new SomeEvent())}> Fire event </button> ); }

However, PostboyProvider only creates and provides the bus. It does not automatically register messages. For that, you still need a registrator.

Root registrator with Context

When using Context, the root registrator should receive the bus from Context instead of importing a singleton.

// postboy/PostboyRoot.tsx import {ReactNode, useEffect, useMemo, useState} from 'react'; import { PostboyAbstractRegistrator, PostboyService } from '@artstesh/postboy'; import { PostboyProvider, usePostboy } from './PostboyContext'; import {ButtonClickedEvent} from '../messages/events/ButtonClickedEvent'; class RootRegistrator extends PostboyAbstractRegistrator { constructor(postboy: PostboyService) { super(postboy); } protected _up(): void { this.recordSubject(ButtonClickedEvent); } } function RootRegistratorScope({children}: { children: ReactNode }) { const postboy = usePostboy(); const registrator = useMemo(() => { return new RootRegistrator(postboy); }, [postboy]); const [ready, setReady] = useState(false); useEffect(() => { registrator.up(); setReady(true); return () => { registrator.down(); setReady(false); }; }, [registrator]); if (!ready) { return null; } return <>{children}</>; } export function PostboyRoot({children}: { children: ReactNode }) { return ( <PostboyProvider> <RootRegistratorScope> {children} </RootRegistratorScope> </PostboyProvider> ); }

This file defines three things:

  1. RootRegistrator — registers global messages and handlers.

  2. RootRegistratorScope — activates the registrator and renders children only after registration is ready.

  3. PostboyRoot — combines PostboyProvider and RootRegistratorScope.

The ready flag is important. It prevents child components from mounting before the root registrator has activated its channels.

Using PostboyRoot

Now wrap your application with PostboyRoot instead of using PostboyProvider directly.

// main.tsx import React from 'react'; import ReactDOM from 'react-dom/client'; import {App} from './App'; import {PostboyRoot} from './postboy/PostboyRoot'; ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <PostboyRoot> <App/> </PostboyRoot> </React.StrictMode> );

The application tree is now created in this order:

  1. PostboyRoot renders PostboyProvider;

  2. PostboyProvider creates a PostboyService;

  3. RootRegistratorScope receives that service through usePostboy();

  4. RootRegistratorScope calls registrator.up();

  5. after activation, it renders App;

  6. child components can safely subscribe to root messages.

This is the Context-based equivalent of activating a singleton registrator before rendering the React tree.

Using the bus from components with Context

When Context is used, do not import a singleton postboy. Use usePostboy().

// EventDisplay.tsx import {useEffect, useState} from 'react'; import {usePostboy} from './postboy/PostboyContext'; import {ButtonClickedEvent} from './messages/events/ButtonClickedEvent'; export function EventDisplay() { const postboy = usePostboy(); const [logs, setLogs] = useState<string[]>([]); useEffect(() => { const subscription = postboy.sub(ButtonClickedEvent).subscribe(event => { setLogs(previous => [ `[${new Date().toLocaleTimeString()}] ${event.buttonName} clicked`, ...previous ]); }); return () => { subscription.unsubscribe(); }; }, [postboy]); return ( <ul> {logs.map((log, index) => ( <li key={index}>{log}</li> ))} </ul> ); }

A publisher looks similar:

// DemoButton.tsx import {usePostboy} from './postboy/PostboyContext'; import {ButtonClickedEvent} from './messages/events/ButtonClickedEvent'; export function DemoButton() { const postboy = usePostboy(); const handleClick = () => { postboy.fire(new ButtonClickedEvent('Demo button')); }; return ( <button onClick={handleClick}> Click me </button> ); }

The important rule is consistency:

  • singleton setup → import postboy;

  • Context setup → use usePostboy().

Do not mix both patterns in the same scope unless you intentionally use multiple buses.

Choosing between singleton and Context

Use the singleton approach when:

  • the application is a simple client-side SPA;

  • one global bus is enough;

  • you want minimal setup;

  • SSR is not involved;

  • tests can work with module-level imports.

Use the Context approach when:

  • you use SSR or Next.js;

  • you need one bus per rendered tree;

  • you want to replace the bus in tests;

  • you build isolated widgets;

  • you work with microfrontends;

  • you need multiple independent communication scopes.

For a first React integration, start with the singleton approach. Move to Context when the application needs explicit bus ownership.

Feature registrators

Feature-specific communication should usually be registered by a feature registrator, not by the root registrator.

This is useful for:

  • route components;

  • dialogs;

  • feature pages;

  • dashboards;

  • embedded widgets;

  • microfrontend entry points;

  • temporary workflows.

// features/products/products.registrator.ts import { PostboyAbstractRegistrator, PostboyService } from '@artstesh/postboy'; import {ProductSelectedEvent} from './messages/ProductSelectedEvent'; export class ProductsRegistrator extends PostboyAbstractRegistrator { constructor(postboy: PostboyService) { super(postboy); } protected _up(): void { this.recordSubject(ProductSelectedEvent); } }

With Context:

// features/products/ProductsPage.tsx import {ReactNode, useEffect, useMemo, useState} from 'react'; import {usePostboy} from '../../postboy/PostboyContext'; import {ProductsRegistrator} from './products.registrator'; function ProductsScope({children}: { children: ReactNode }) { const postboy = usePostboy(); const registrator = useMemo(() => { return new ProductsRegistrator(postboy); }, [postboy]); const [ready, setReady] = useState(false); useEffect(() => { registrator.up(); setReady(true); return () => { registrator.down(); setReady(false); }; }, [registrator]); if (!ready) { return null; } return <>{children}</>; } export function ProductsPage() { return ( <ProductsScope> <ProductsContent/> </ProductsScope> ); } function ProductsContent() { return ( <div> Products feature UI </div> ); }

The scope component ensures that feature children are rendered only after the feature registrator is active.

With a singleton bus, the same idea can be implemented by importing postboy instead of using usePostboy().

A small helper hook for registrators

If you use feature registrators often, you can create a small hook.

// postboy/usePostboyRegistrator.ts import {useEffect, useMemo, useState} from 'react'; import { PostboyAbstractRegistrator, PostboyService } from '@artstesh/postboy'; export function usePostboyRegistrator<T extends PostboyAbstractRegistrator>( postboy: PostboyService, factory: (postboy: PostboyService) => T ): boolean { const registrator = useMemo(() => { return factory(postboy); }, [postboy, factory]); const [ready, setReady] = useState(false); useEffect(() => { registrator.up(); setReady(true); return () => { registrator.down(); setReady(false); }; }, [registrator]); return ready; }

Usage:

// features/products/ProductsPage.tsx import {useCallback} from 'react'; import {usePostboy} from '../../postboy/PostboyContext'; import {usePostboyRegistrator} from '../../postboy/usePostboyRegistrator'; import {ProductsRegistrator} from './products.registrator'; export function ProductsPage() { const postboy = usePostboy(); const createRegistrator = useCallback( () => new ProductsRegistrator(postboy), [postboy] ); const ready = usePostboyRegistrator(postboy, createRegistrator); if (!ready) { return null; } return ( <ProductsContent/> ); }

This pattern is optional. It can reduce repetition, but the explicit scope component is often easier to understand at first.

Subscriptions in React components

Postboy subscriptions are RxJS subscriptions. Manage them like normal React effect resources.

import {useEffect, useState} from 'react'; import {usePostboy} from '../postboy/PostboyContext'; import {UserLoggedInEvent} from '../messages/events/UserLoggedInEvent'; export function UserMenu() { const postboy = usePostboy(); const [userName, setUserName] = useState<string | null>(null); useEffect(() => { const subscription = postboy.sub(UserLoggedInEvent).subscribe(event => { setUserName(event.userName); }); return () => { subscription.unsubscribe(); }; }, [postboy]); return ( <span>{userName ?? 'Guest'}</span> ); }

This is standard React cleanup. Postboy does not require a React-specific unsubscribe mechanism.

For general message subscription patterns, see Generic messages and Callback messages.

Do not use the bus during render

React render should stay pure. Avoid calling methods such as fire, fireCallback, or side-effecting exec calls directly during render.

Avoid this:

function ProductCard({id}: { id: number }) { postboy.fire(new ProductViewedEvent(id)); return <div>Product {id}</div>; }

Prefer effects or event handlers:

function ProductCard({id}: { id: number }) { useEffect(() => { postboy.fire(new ProductViewedEvent(id)); }, [id]); return <div>Product {id}</div>; }

Event handlers are also safe places for publishing messages:

function AddToCartButton({productId}: { productId: number }) { const handleClick = () => { postboy.fire(new ProductAddedToCartEvent(productId)); }; return ( <button onClick={handleClick}> Add to cart </button> ); }

The same rule applies to fireCallback: call it in an effect, event handler, or application service layer — not as part of render.

React Strict Mode

In development, React Strict Mode may intentionally mount, unmount, and mount components again to detect unsafe side effects.

This can expose lifecycle bugs such as:

  • duplicate registrations;

  • missing cleanup;

  • subscriptions that are not unsubscribed;

  • registrators that call up() but never call down().

Always pair up() with down() in effect cleanup:

useEffect(() => { registrator.up(); return () => { registrator.down(); }; }, [registrator]);

If a setup action must run only once for the whole application lifetime, consider activation before React rendering. Do this only for truly global setup and keep it predictable for tests.

Strict Mode is not a problem by itself. It helps reveal lifecycle mistakes earlier.

Server-side rendering and Next.js

When using SSR frameworks such as Next.js, be careful with module-level singletons.

A module singleton can be shared between requests on the server. This may lead to data leaking between users if request-specific data is stored in the bus or in registered handlers.

For SSR applications, prefer Context-based bus creation.

In Next.js App Router, client-side Postboy usage should live in Client Components:

// app/ClientPostboyRoot.tsx 'use client'; import {ReactNode} from 'react'; import {PostboyRoot} from '../postboy/PostboyRoot'; export function ClientPostboyRoot({children}: { children: ReactNode }) { return ( <PostboyRoot> {children} </PostboyRoot> ); }

Then use it from your layout:

// app/layout.tsx import {ReactNode} from 'react'; import {ClientPostboyRoot} from './ClientPostboyRoot'; export default function RootLayout({children}: { children: ReactNode }) { return ( <html lang="en"> <body> <ClientPostboyRoot> {children} </ClientPostboyRoot> </body> </html> ); }

Use a module singleton only when you are sure the code runs only in the browser or does not store request-specific state.

Root vs feature scope

A practical React rule:

  • use one singleton bus for simple client-side applications;

  • use Context when you need isolated or SSR-safe bus instances;

  • use a root registrator only for global communication;

  • use feature registrators for routes, pages, dialogs, widgets, and temporary UI areas;

  • call up() when the scope starts;

  • call down() when the scope ends;

  • render feature children only after the feature registrator is ready if they subscribe immediately.

Use root scope for:

  • authentication;

  • global notifications;

  • application configuration;

  • theme;

  • global error events;

  • application-wide diagnostics.

Use feature scope for:

  • page-specific communication;

  • dialog-specific communication;

  • route interactions;

  • editor state;

  • feature-local commands and queries;

  • temporary workflows.

This keeps React component ownership and Postboy lifecycle aligned.

Suggested React project structure

One possible structure is:

src/ postboy/ postboy.ts PostboyContext.tsx PostboyRoot.tsx usePostboyRegistrator.ts messages/ events/ queries/ commands/ executors/ features/ products/ ProductsPage.tsx products.registrator.ts products.service.ts messages/ checkout/ CheckoutPage.tsx checkout.registrator.ts messages/

The exact structure is up to your application, but the important rule is ownership:

  • global messages should be easy to find globally;

  • feature messages should live near the feature that owns them;

  • registrators should be located close to the scope they activate;

  • hooks and providers should be grouped in a clear integration layer.

For naming conventions and message roles, see Message roles.

Common React mistakes

Creating the bus inside a component render

This creates unstable bus instances and can break subscriptions.

Create the bus as a module singleton or through a memoized provider.

Mixing singleton and Context accidentally

If the registrator uses a singleton bus, but components use a Context bus, they are talking to different Postboy instances.

Choose one pattern for a scope:

  • singleton imports everywhere;

  • or Context with usePostboy() everywhere.

Calling fire or fireCallback during render

Render should be pure. Use useEffect, event handlers, or service functions.

Activating a root registrator too late

If children subscribe in their effects, a parent effect may be too late depending on your tree and timing assumptions.

For simple global setup, activate the root registrator before rendering React. For Context setup, use a PostboyRoot that renders children only after the registrator is ready.

Activating a feature registrator too late

If a component subscribes before the feature registrator is activated, the message channel may not exist yet.

Use a feature scope component and render feature children only after up() has completed.

Forgetting cleanup in useEffect

Always unsubscribe subscriptions and call registrator.down() in cleanup.

Registering all messages in the root registrator

This makes cleanup harder and turns the root registrator into a global dependency hub.

Use feature registrators for feature-owned messages.

Ignoring Strict Mode behavior

Development-only double mounting can reveal missing cleanup. Treat it as a useful signal, not as a React bug.

Using a singleton bus for request-specific SSR state

In SSR environments, prefer Context-based per-boundary bus creation to avoid leaking state between requests.

Using different imports for the same message class

Make sure the class registered by the registrator is the same class used by publishers and subscribers. Avoid duplicate barrels or inconsistent import paths that can lead to different runtime references.

Troubleshooting

"There is no registered event"

Check that:

  • the message is registered in a registrator;

  • the registrator instance was created;

  • up() was called before using the message;

  • the message belongs to the scope where it is being used;

  • the same message class reference is used in registration and usage;

  • the component is not trying to use the bus during render before setup is complete;

  • the registrator and component use the same Postboy instance.

For more details, see Best Practices & Anti‑patterns.

Event handler runs twice in development

If you use React Strict Mode, effects may run twice during development through mount/unmount/remount checks.

Check that:

  • down() is called in effect cleanup;

  • subscriptions are unsubscribed;

  • registration logic is safe for the expected lifecycle;

  • the duplicate behavior does not happen in production builds.

Feature messages still react after navigation

Check that:

  • the feature registrator is activated by the route/page component;

  • down() is called when the component unmounts;

  • the message was not registered globally by mistake;

  • long-lived modules are not keeping independent subscriptions.

Callback never returns a value

The callback handler may receive the message but never complete it.

Check the general callback message documentation: Callback messages.

Component does not update after a message

Check that:

  • the subscription is active;

  • the message is fired after the subscription is created;

  • the state update uses React state setters;

  • the component is still mounted;

  • the update is not hidden by stale closures.

When updating state from subscriptions, prefer functional updates if the new value depends on the previous value:

setCount(previous => previous + 1);

Migration tips for React projects

From prop drilling

Use Postboy when communication crosses many component levels or when the sender should not know the receiver.

Do not replace simple parent-child props with a bus unnecessarily. Props are still the clearest option for local component relationships.

From Context-only communication

React Context is good for dependency access and relatively stable shared values.

Postboy is useful when you need explicit event-like communication, commands, or request/response flows between parts of the application.

A common pattern is to use Context to provide the Postboy bus, and Postboy messages to model communication.

From Redux, Zustand, MobX, or other stores

Postboy is not a state management library.

Keep dedicated stores for application state. Use Postboy for:

  • events;

  • commands;

  • side-effect orchestration;

  • cross-feature communication;

  • request/response flows;

  • decoupling modules that should not call each other directly.

From a simple EventEmitter

Replace untyped string events with typed message classes.

A simple migration path is:

  • event name → message class;

  • emit(...)postboy.fire(...);

  • on(...)postboy.sub(...).subscribe(...);

  • manual cleanup → subscriptions or registrator lifecycle.

Moving to RxJS 8

When your stack moves to RxJS 8, use the Postboy 4.x line.

Check:

  • RxJS operator changes in your application code;

  • dependencies that still require RxJS 7;

  • Postboy version alignment;

  • test setup and mocks that depend on RxJS behavior.

Summary

In React, Postboy works best when its lifecycle is aligned with component ownership:

  1. Use a singleton bus for the simplest client-side setup.

  2. Activate global registrators before rendering React when children subscribe immediately.

  3. Use Context when you need isolated, replaceable, or SSR-safe bus instances.

  4. Use PostboyRoot to combine Context-based bus creation and root registration.

  5. Use feature registrators for routes, dialogs, widgets, and temporary UI areas.

  6. Render feature children only after their registrator is ready if they subscribe on mount.

  7. Manage component subscriptions like normal RxJS subscriptions.

  8. Do not publish, subscribe, or call callbacks during render.

  9. Be aware of React Strict Mode and SSR boundaries.

  10. Use the Postboy major version that matches your RxJS generation.

For message types, registration APIs, namespaces, middleware, and general architecture patterns, use the dedicated documentation sections linked at the top of this guide.

06 июня 2026