Skip to content

Conversation

@ryanbas21
Copy link
Collaborator

@ryanbas21 ryanbas21 commented Jan 20, 2026

JIRA Ticket

https://pingidentity.atlassian.net/browse/SDKS-4715

Description

Implement error handling throughout the api surface rather than undefined

Summary by CodeRabbit

  • Breaking Changes
    • Major version updates across ForgeRock packages require migration.
    • Journey client methods (start, next, resume, terminate) now return standardized error objects instead of undefined when failures occur.
    • Error handling aligned with DaVinci client conventions.
    • Migration guide provided to detect and handle new error response format.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Jan 20, 2026

🦋 Changeset detected

Latest commit: c2ead9b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@forgerock/storage Major
@forgerock/sdk-oidc Major
@forgerock/journey-client Major
@forgerock/oidc-client Major
@forgerock/davinci-client Major
@forgerock/device-client Major
@forgerock/protect Major
@forgerock/sdk-types Major
@forgerock/sdk-utilities Major
@forgerock/iframe-manager Major
@forgerock/sdk-logger Major
@forgerock/sdk-request-middleware Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

The pull request introduces breaking changes across multiple packages with major version bumps to the Journey client error handling. The start, next, and resume methods now return GenericError objects instead of undefined when encountering unknown step types or server errors. The terminate method's return type is updated to include GenericError. The resume method logic is expanded to parse URL parameters and retrieve previous steps from storage.

Changes

Cohort / File(s) Summary
Changeset
.changeset/chilly-sheep-follow.md
Documents breaking changes with major version bumps. Updates return type tables for Journey client methods (start, next, resume, terminate) to include GenericError. Includes migration guide showing error detection via error property.
Error Handling Implementation
packages/journey-client/src/lib/client.store.ts
start and next now return GenericError instead of undefined on server failure. resume expanded to parse URL parameters (code, state, form_post_entry, responsekey), retrieve previous step from storage with error handling, and route through next or start. terminate updated to return void | GenericError with contextual error messages.
Step Object Creation
packages/journey-client/src/lib/journey.utils.ts
createJourneyObject now returns GenericError instead of undefined for unrecognized step types. Logic determines step type via authId, successUrl, or defaults to LoginFailure. Adds documentation and exports the function as public API.
Test Updates
packages/journey-client/src/lib/client.store.test.ts
Adds GenericError type import and introduces local isGenericError type guard. Extends mockStorageInstance with set and remove methods. Tests refactored to assert non-error results using type guard.
Type Annotation Update
packages/journey-client/src/lib/device/device-profile.test.ts
Replaces SpyInstance with MockInstance from vitest for test spy variable type annotation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • cerebrl

Poem

🐰 A journey now with errors clear,
No more undefined left to fear,
GenericError stands so bright,
Handling failures just right,
The client hops through storage's might! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title uses vague, hyphenated phrasing ('update-error-handling-across-packages') that obscures the specific change; it's generic and doesn't clearly convey the main objective. Revise the title to be more specific and descriptive, such as 'fix!: Return GenericError instead of undefined in journey-client methods' to clearly communicate the primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required JIRA ticket link and a brief statement of purpose, satisfying the template structure; it adequately conveys the intent despite being concise.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link
Contributor

nx-cloud bot commented Jan 20, 2026

View your CI Pipeline Execution ↗ for commit c2ead9b

Command Status Duration Result
nx run-many -t build --no-agents ✅ Succeeded <1s View ↗
nx affected -t build lint test e2e-ci ✅ Succeeded 4m 36s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-20 22:57:21 UTC

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/journey-client/src/lib/client.store.ts (1)

156-176: Unsafe type assertion may cause runtime issues.

On line 166, createJourneyObject(stored.step) as JourneyStep is unsafe. If stored.step lacks authId, createJourneyObject returns JourneyLoginFailure (not JourneyStep), which would then be incorrectly typed and passed to self.next().

Consider validating the result type before proceeding:

🐛 Proposed fix
         } else if (isStoredStep(stored)) {
-          previousStep = createJourneyObject(stored.step) as JourneyStep;
+          const journeyObject = createJourneyObject(stored.step);
+          if ('type' in journeyObject && journeyObject.type === 'Step') {
+            previousStep = journeyObject as JourneyStep;
+          } else if (isGenericError(journeyObject)) {
+            throw new Error(`Error recreating step from storage: ${journeyObject.message || journeyObject.error}`);
+          } else {
+            throw new Error('Stored step is not a valid Step type for resume operation.');
+          }
         }
🤖 Fix all issues with AI agents
In @.changeset/chilly-sheep-follow.md:
- Around line 25-40: The "After:" label and the following TypeScript example are
accidentally inside the fenced code block; update the changeset so the initial
code block ends before the "After:" label, place "After:" on its own line, then
open a new ```ts fenced block containing the result example (the const result =
await client.start() snippet and its if/else handling) and close that
fence—ensure the original "Before" code block (const step = await
client.start();) remains unchanged and that both fences are properly balanced
around the examples.
- Around line 1-6: Remove the '@forgerock/storage' entry from this changeset
header so it no longer lists a major bump; edit the top YAML list to include
only '@forgerock/sdk-oidc', '@forgerock/journey-client', and
'@forgerock/oidc-client' (leaving their versions as-is) because the storage
package has no changes in this PR and its API changes were already handled in
the separate changeset referenced by SDKS-4361/hip-owls-rule.md.

In `@packages/journey-client/src/lib/client.store.test.ts`:
- Around line 17-22: The test's type guard isGenericError currently checks for
'error' and 'type' but production's guard checks for 'error' and 'message';
update isGenericError in client.store.test.ts to check for 'error' in result &&
'message' in result to match the production check (or refactor by extracting a
shared isGenericError utility and import it into both the test and
client.store.ts so both use the identical implementation).
🧹 Nitpick comments (1)
packages/journey-client/src/lib/journey.utils.ts (1)

40-53: The default case is unreachable given the current logic.

The if-else chain (lines 32-38) guarantees type is always one of StepType.Step, StepType.LoginSuccess, or StepType.LoginFailure. The switch exhaustively handles all three values, making the default case dead code.

Consider using TypeScript's exhaustive check pattern to catch future enum additions at compile time:

♻️ Suggested refactor using exhaustive check
   switch (type) {
     case StepType.LoginSuccess:
       return createJourneyLoginSuccess(step);
     case StepType.LoginFailure:
       return createJourneyLoginFailure(step);
     case StepType.Step:
       return createJourneyStep(step);
     default:
-      return {
-        error: 'unknown_step_type',
-        message: 'Unable to determine step type from server response',
-        type: 'unknown_error',
-      };
+      // Exhaustive check - TypeScript will error if a case is missed
+      const _exhaustiveCheck: never = type;
+      return {
+        error: 'unknown_step_type',
+        message: `Unable to determine step type from server response: ${_exhaustiveCheck}`,
+        type: 'unknown_error',
+      };
   }

Comment on lines +1 to +6
---
'@forgerock/storage': major
'@forgerock/sdk-oidc': major
'@forgerock/journey-client': major
'@forgerock/oidc-client': major
---
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

git diff --name-only | grep -E "(storage|changeset)" | head -30

Repository: ForgeRock/ping-javascript-sdk

Length of output: 55


🏁 Script executed:

# Check for storage package modifications across all package paths
fd --type f -e ts -e json . packages/ 2>/dev/null | grep -i storage | grep -v node_modules | head -30

Repository: ForgeRock/ping-javascript-sdk

Length of output: 497


🏁 Script executed:

# Look at the changeset file context and any related storage changes
cat .changeset/chilly-sheep-follow.md 2>/dev/null || echo "File not found"

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1877


🏁 Script executed:

# Search for GenericError in storage packages to understand the API change
rg "GenericError" --type ts packages/ 2>/dev/null | grep -E "(storage|sdk-effects)" | head -20

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1706


🏁 Script executed:

# Check if storage files were modified in this PR
git diff --name-only HEAD | grep -i storage

Repository: ForgeRock/ping-javascript-sdk

Length of output: 55


🏁 Script executed:

# Check the actual storage.effects.ts file to see the current API
cat -n packages/sdk-effects/storage/src/lib/storage.effects.ts | head -50

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1695


🏁 Script executed:

# Search for any recent changes or TODOs related to storage error handling
rg -n "TODO|FIXME|GenericError" packages/sdk-effects/storage/src/lib/storage.effects.ts -B2 -A2

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1229


🏁 Script executed:

# Check if there are multiple changeset entries for storage
find .changeset -type f -name "*.md" ! -name ".gitkeep" -exec grep -l "storage" {} \;

Repository: ForgeRock/ping-javascript-sdk

Length of output: 134


🏁 Script executed:

cat .changeset/hip-owls-rule.md

Repository: ForgeRock/ping-javascript-sdk

Length of output: 522


🏁 Script executed:

# Also verify if storage package has any actual code changes
rg -n "export" packages/sdk-effects/storage/src/lib/storage.effects.ts | head -20

Repository: ForgeRock/ping-javascript-sdk

Length of output: 361


Remove @forgerock/storage from this changeset.

The changeset marks @forgerock/storage as a major version bump, but the storage package has no changes in this PR. The storage API's transition to return GenericError | null was already completed in SDKS-4361 and is documented in the separate hip-owls-rule.md changeset. The breaking changes described here apply only to journey-client methods, not storage.

🤖 Prompt for AI Agents
In @.changeset/chilly-sheep-follow.md around lines 1 - 6, Remove the
'@forgerock/storage' entry from this changeset header so it no longer lists a
major bump; edit the top YAML list to include only '@forgerock/sdk-oidc',
'@forgerock/journey-client', and '@forgerock/oidc-client' (leaving their
versions as-is) because the storage package has no changes in this PR and its
API changes were already handled in the separate changeset referenced by
SDKS-4361/hip-owls-rule.md.

Comment on lines +25 to +40
Before:

```ts
const step = await client.start();
if (step) {
// Use step
}

After: const result = await client.start();
if ('error' in result) {
// Handle error
console.error(result.message);
} else {
// Use step
}
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Migration guide has a formatting issue.

The "After:" section on line 33 is incorrectly placed inside the code block. This will render incorrectly in the changeset documentation.

📝 Suggested fix
 Before:
 
 ```ts
 const step = await client.start();
 if (step) {
   // Use step
 }
+```
 
-After: const result = await client.start();
+After:
+
+```ts
+const result = await client.start();
 if ('error' in result) {
   // Handle error
   console.error(result.message);
 } else {
   // Use step
 }
 ```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Before:
```ts
const step = await client.start();
if (step) {
// Use step
}
After: const result = await client.start();
if ('error' in result) {
// Handle error
console.error(result.message);
} else {
// Use step
}
```
Before:
🤖 Prompt for AI Agents
In @.changeset/chilly-sheep-follow.md around lines 25 - 40, The "After:" label
and the following TypeScript example are accidentally inside the fenced code
block; update the changeset so the initial code block ends before the "After:"
label, place "After:" on its own line, then open a new ```ts fenced block
containing the result example (the const result = await client.start() snippet
and its if/else handling) and close that fence—ensure the original "Before" code
block (const step = await client.start();) remains unchanged and that both
fences are properly balanced around the examples.

Comment on lines +17 to +22
/**
* Type guard to check if a result is a GenericError
*/
function isGenericError(result: unknown): result is GenericError {
return typeof result === 'object' && result !== null && 'error' in result && 'type' in result;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent type guard implementations.

This type guard checks for 'error' in result && 'type' in result, while the production code in client.store.ts (lines 142-143) checks for 'error' in obj && 'message' in obj. Consider aligning both guards to check the same properties for consistency.

♻️ Suggested alignment
 function isGenericError(result: unknown): result is GenericError {
-  return typeof result === 'object' && result !== null && 'error' in result && 'type' in result;
+  return typeof result === 'object' && result !== null && 'error' in result && 'message' in result;
 }

Or consider extracting a shared isGenericError utility that both test and production code can import.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Type guard to check if a result is a GenericError
*/
function isGenericError(result: unknown): result is GenericError {
return typeof result === 'object' && result !== null && 'error' in result && 'type' in result;
}
/**
* Type guard to check if a result is a GenericError
*/
function isGenericError(result: unknown): result is GenericError {
return typeof result === 'object' && result !== null && 'error' in result && 'message' in result;
}
🤖 Prompt for AI Agents
In `@packages/journey-client/src/lib/client.store.test.ts` around lines 17 - 22,
The test's type guard isGenericError currently checks for 'error' and 'type' but
production's guard checks for 'error' and 'message'; update isGenericError in
client.store.test.ts to check for 'error' in result && 'message' in result to
match the production check (or refactor by extracting a shared isGenericError
utility and import it into both the test and client.store.ts so both use the
identical implementation).

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 38.46154% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 18.83%. Comparing base (b89ad58) to head (c2ead9b).
⚠️ Report is 29 commits behind head on main.

Files with missing lines Patch % Lines
packages/journey-client/src/lib/client.store.ts 27.02% 27 Missing ⚠️
packages/journey-client/src/lib/journey.utils.ts 66.66% 5 Missing ⚠️

❌ Your patch status has failed because the patch coverage (38.46%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage.
❌ Your project status has failed because the head coverage (18.83%) is below the target coverage (40.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #524      +/-   ##
==========================================
+ Coverage   18.79%   18.83%   +0.04%     
==========================================
  Files         140      142       +2     
  Lines       27640    27766     +126     
  Branches      980      990      +10     
==========================================
+ Hits         5195     5230      +35     
- Misses      22445    22536      +91     
Files with missing lines Coverage Δ
packages/journey-client/src/lib/journey.utils.ts 87.50% <66.66%> (-5.69%) ⬇️
packages/journey-client/src/lib/client.store.ts 82.43% <27.02%> (-10.36%) ⬇️

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 20, 2026

Open in StackBlitz

@forgerock/davinci-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/davinci-client@524

@forgerock/device-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/device-client@524

@forgerock/journey-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/journey-client@524

@forgerock/oidc-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/oidc-client@524

@forgerock/protect

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/protect@524

@forgerock/sdk-types

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-types@524

@forgerock/sdk-utilities

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-utilities@524

@forgerock/iframe-manager

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/iframe-manager@524

@forgerock/sdk-logger

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-logger@524

@forgerock/sdk-oidc

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-oidc@524

@forgerock/sdk-request-middleware

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-request-middleware@524

@forgerock/storage

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/storage@524

commit: c2ead9b

@github-actions
Copy link
Contributor

Deployed 9b7519c to https://ForgeRock.github.io/ping-javascript-sdk/pr-524/9b7519c0c54f5073e9409b8e42f3c9c422b5f53c branch gh-pages in ForgeRock/ping-javascript-sdk

@github-actions
Copy link
Contributor

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔻 @forgerock/journey-client - 0.0 KB (-82.4 KB, -100.0%)

📊 Minor Changes

📈 @forgerock/journey-client - 83.0 KB (+0.6 KB)

➖ No Changes

@forgerock/device-client - 9.2 KB
@forgerock/oidc-client - 23.4 KB
@forgerock/protect - 150.1 KB
@forgerock/sdk-utilities - 8.5 KB
@forgerock/sdk-types - 8.0 KB
@forgerock/storage - 1.5 KB
@forgerock/sdk-logger - 1.6 KB
@forgerock/iframe-manager - 2.4 KB
@forgerock/sdk-request-middleware - 4.5 KB
@forgerock/sdk-oidc - 2.6 KB
@forgerock/davinci-client - 39.8 KB


13 packages analyzed • Baseline from latest main build

Legend

🆕 New package
🔺 Size increased
🔻 Size decreased
➖ No change

ℹ️ How bundle sizes are calculated
  • Current Size: Total gzipped size of all files in the package's dist directory
  • Baseline: Comparison against the latest build from the main branch
  • Files included: All build outputs except source maps and TypeScript build cache
  • Exclusions: .map, .tsbuildinfo, and .d.ts.map files

🔄 Updated automatically on each push to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants