Skip to content

IS-11380 HaapiStepper: own bootstrap config and the haapiFetch lifecycle#207

Open
aleixsuau wants to merge 2 commits into
integration/IS-5161/login-web-appfrom
fix/integration/IS-5161/login-web-app/IS-11380-stepper-haapi-fetch-lifecycle
Open

IS-11380 HaapiStepper: own bootstrap config and the haapiFetch lifecycle#207
aleixsuau wants to merge 2 commits into
integration/IS-5161/login-web-appfrom
fix/integration/IS-5161/login-web-app/IS-11380-stepper-haapi-fetch-lifecycle

Conversation

@aleixsuau
Copy link
Copy Markdown
Contributor

Jira: https://curity.atlassian.net/browse/IS-11380

Summary

  • HaapiStepper's bootstrap config (initial URL + HAAPI config) is now overridable via the config prop. Apps can pass their own <HaapiStepper config={{ bootstrap }}>; omitting it keeps the previous behaviour (the module-level configuration singleton from window.__CONFIG__).
  • Replaced the module-load haapi-fetch-initializer.ts singleton with a new useHaapiFetch hook. It builds the HAAPI fetcher from the supplied config and returns a ready-to-call sendHaapiFetchRequest.
  • The hook keeps a single fetcher alive for the page (matching the driver's "one active fetcher" rule), so React StrictMode's double-invoke no longer trips Already disposed errors during dev.
  • processHaapiNextStep now takes a single named-params object instead of eight positional arguments — easier to read and to extend.

@aleixsuau aleixsuau marked this pull request as ready for review May 27, 2026 13:46
Copy link
Copy Markdown
Contributor

@luisgoncalves luisgoncalves left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍
Added a couple of comments that I think need attention.

Comment thread src/login-web-app/src/haapi-stepper/data-access/useHaapiFetch.ts
import { handleAuthenticationOrRegistrationStep } from './step-handlers/authentication-or-registration-step';

const DEFAULT_CONFIG: Required<HaapiStepperConfig> = {
bootstrap: configuration,
Copy link
Copy Markdown
Contributor

@luisgoncalves luisgoncalves May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes from the import from bootstrap-configuration, which eagerly checks for window.__CONFIG__ to be present and bombs if not.

In a scenario where the consumer wants to override, it would still bomb, right?

Since configResult is already memoized, perhaps we could build it slightly differently, and only load the bootstrap config if one was not provided via prop? We may need to expose a function to load window config, instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good catch, thanks 🙏 ! I just pushed a refactor that decouples app and library configuration consumption and polishes the standalone (library) mode:

  • Two configuration modes are first-class: served (LWA default — reads window.CONFIG) and standalone (library — consumer passes config.bootstrap). The window.CONFIG read is lazy now (inside resolveStepperConfig), so the override prop is actually reachable from third-party apps.
  • Missing config on both sides → actionable error at first render naming both recovery paths.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Makes HaapiStepper's bootstrap (initial URL + HAAPI config) overridable via the config prop and replaces the module-load haapi-fetch-initializer singleton with a useHaapiFetch hook that caches a single fetcher to survive React StrictMode's double-invoke. Also refactors processHaapiNextStep to take a single named-params object.

Changes:

  • Introduce useHaapiFetch hook + cached FetchLike; thread the fetcher explicitly through sendHaapiFetchRequest; delete haapi-fetch-initializer.ts.
  • Move HaapiStepperConfig into haapi-stepper.types.ts, add bootstrap: BootstrapConfiguration to it, and use it both for defaults and via Partial<HaapiStepperConfig> on the props.
  • Refactor processHaapiNextStep to a single params object and update recursive call sites and tests accordingly.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/login-web-app/src/haapi-stepper/data-access/useHaapiFetch.ts New hook that builds/caches the HAAPI fetcher and returns a bound sendHaapiFetchRequest.
src/login-web-app/src/haapi-stepper/data-access/useHaapiFetch.spec.ts New tests verifying fetcher creation and link/form request forwarding.
src/login-web-app/src/haapi-stepper/data-access/happi-fetch-request.ts sendHaapiFetchRequest now takes the FetchLike as a parameter instead of importing the singleton.
src/login-web-app/src/haapi-stepper/data-access/haapi-fetch-initializer.ts Removed; replaced by useHaapiFetch.
src/login-web-app/src/haapi-stepper/data-access/index.ts Re-export the new useHaapiFetch hook.
src/login-web-app/src/haapi-stepper/feature/stepper/HaapiStepper.tsx Wire useHaapiFetch, use bootstrap from merged config for initial URL, refactor processHaapiNextStep to a params object.
src/login-web-app/src/haapi-stepper/feature/stepper/haapi-stepper.types.ts Move HaapiStepperConfig here and add bootstrap: BootstrapConfiguration.
src/login-web-app/src/haapi-stepper/feature/stepper/data-formatters/polling-step.ts Import HaapiStepperConfig from its new location.
src/login-web-app/src/haapi-stepper/feature/stepper/step-handlers/authentication-or-registration-step.ts Same import-source update.
src/login-web-app/src/haapi-stepper/feature/stepper/step-handlers/completed-with-success-step.ts Same import-source update.
src/login-web-app/src/haapi-stepper/feature/stepper/HaapiStepper.spec.tsx Mock @curity/identityserver-haapi-web-driver directly, add haapi to mock bootstrap, add override-bootstrap test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +23 to +30
let cachedHaapiFetch: FetchLike | undefined;

function getHaapiFetch(haapi: HaapiConfiguration): FetchLike {
return (cachedHaapiFetch ??= createHaapiFetch(haapi));
}

export function useHaapiFetch(haapi: HaapiConfiguration) {
const haapiFetch = useMemo(() => getHaapiFetch(haapi), [haapi]);
aleixsuau and others added 2 commits May 29, 2026 08:48
…cle.

- Add bootstrap: BootstrapConfiguration to HaapiStepperConfig (single
  field, defaults to the module-level configuration singleton). Override
  via <HaapiStepper config={{ bootstrap }}>.
- Introduce useHaapiFetch(haapi) hook in data-access/. Owns the
  haapiFetch lifecycle via a module-level single-slot cache (driver is a
  process-global, one active fetcher per page). Returns a bound
  sendHaapiFetchRequest.
- sendHaapiFetchRequest(action, haapiFetch: FetchLike) becomes pure.
  haapi-fetch-initializer.ts removed.
- Move HaapiStepperConfig to haapi-stepper.types.ts (CONFIG TYPINGS).
- Refactor processHaapiNextStep to a single named-params object.
- Re-export useHaapiFetch from data-access/index.ts.
- Tests: new useHaapiFetch.spec.ts (binding to config, link routing,
  form routing); new bootstrap-override case in HaapiStepper.spec.tsx.
…standalone-mode support.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aleixsuau aleixsuau force-pushed the fix/integration/IS-5161/login-web-app/IS-11380-stepper-haapi-fetch-lifecycle branch from 6e9cfc6 to 5319c8b Compare May 29, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants