Files
skills/docs/ui/react/react-ui/src/pack/pack-registry-provider/pack-registry-provider.md
2026-05-29 08:20:56 +01:00

3.1 KiB

<PackRegistryProvider> — chassis pack registry

(no submodules)

Purpose

Mounts the active pack registry, validates every pack against ComponentPackSchema plus the no-collision invariant, runs each pack's onRegister(ctx) hook in declared order on mount, runs onUnregister(ctx) in reverse order on unmount, forwards each pack's translation bundles into the active i18n catalog under the pack's name as the namespace, and emits the OTel signals defined in the proposal.

Features

  • Validates packs synchronously at mount; throws ReactUiError(REACT_UI.PACK_NAME_COLLISION) when two packs share a name
  • Registration in declared order; teardown in reverse order
  • Each pack receives a PackContext containing the active i18n instance, active theme, a PackLoggerLike (defaulting to a console-backed shim), and an AbortSignal scoped to the pack's mount lifetime
  • Pack translations auto-registered via i18n.catalog.set(locale, packName, bundle) so consumers reading t('packName:key') see the registered values
  • peerRange mismatch logs a structured warning AND increments react_ui.pack.version_mismatch_total — the pack still registers (degrades gracefully, never throws)
  • Runtime override map (<ReactUiProvider components={...}>) merges on top of pack defaults at registration time
  • OTel: counters react_ui.pack.register_total, react_ui.pack.unregister_total, react_ui.pack.version_mismatch_total; span react_ui.pack.register{name} around each onRegister

Usage: Basic example

import { PackRegistryProvider } from "@suaveplan/react-ui/pack/pack-registry-provider";

<PackRegistryProvider i18n={i18n} packs={[authPack]}>
    <App />
</PackRegistryProvider>;

Usage: Advanced example

import { PackRegistryProvider } from "@suaveplan/react-ui/pack/pack-registry-provider";

<PackRegistryProvider
    i18n={i18n}
    packs={[authPack, socialPack, billingPack]}
    components={{
        auth: { LoginForm: AcmeLoginForm },
        social: { ShareButton: AcmeShareButton },
    }}
    logger={{ warn: log.warn, info: log.info }}
>
    <App />
</PackRegistryProvider>;

API Reference

  • <PackRegistryProvider> — props per PackRegistryProviderProps:
    • i18n: I18nInstance — required; pack translations register here
    • packs: ReadonlyArray<ComponentPack> — required
    • components?: RuntimeComponentOverride — optional override map
    • logger?: PackLoggerLike — optional; defaults to a console-backed shim
    • children: ReactNode

Implementation notes

The provider enforces TWO validation passes at mount time: the collision check (synchronous, throws on duplicate name) and the schema check (synchronous, throws on bad shape). Both run BEFORE any onRegister hook fires so a partially-registered registry never exists. onRegister runs inside an OTel span so failures inside a pack's hook are attributable to the pack name in trace storage. The teardown loop iterates in reverse so packs that depend on earlier packs (e.g. a billing pack assuming auth is mounted) tear down in the safe order.